model_validator 1.0.0 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64f760c55b0d9771afce630e56523e689a3bf1ebd65f21acc003009518f1c340
4
- data.tar.gz: 5854b1987c516583bd2e50a8b97ff576594a6bd9cb3fc1157262ce2995cd4cd4
3
+ metadata.gz: ad05f1a13e54602959a5913973a2faed03b80203233285d48b692fd3310a6b81
4
+ data.tar.gz: a5cf56f9d5d792f675c4ccc918b448772ad4af4d02bdd2647b2a697c0c15b6d6
5
5
  SHA512:
6
- metadata.gz: 6550ec508bfa1a5670f6ad3548e3efddc744dd08df7302d7dbbdbe5afd331e59aa44ca4dbe8681172ed6ed0299a500370d98220153d5a7df63fed0025cc86900
7
- data.tar.gz: e66fb4032041a9b6323a70afd95939f8083736b089d3a27e2f09843c266e43d1d414085ae05d5919dadeac8daf6e8416d03378a2a534bf8e3e1b729a810f733c
6
+ metadata.gz: a629d909b30a1582bb07d9bf5b1884911cb1991c6749ba2fb5fbd75b625648536c1f6ce16c6dcf6d39192a19af0326b6d6c7e96b87e507fc86f76cd3d0d02347
7
+ data.tar.gz: e0440d447f4c11cb7f9fa9a027963476181d1114f18ed9a3fa2e00e4822bd7fd22b8e11ad7f1e019cf57e57d5f45bf9e6a8bc9317b9c9a09fecdf7ea486a3548
data/Gemfile CHANGED
@@ -4,12 +4,10 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
+ gem "coveralls", require: false
7
8
  gem "rake", "~> 13.0"
8
9
  gem "rspec", "~> 3.0"
9
10
  gem "rubocop", "~> 1.7"
10
-
11
- gem "sqlite3", "~> 1.4"
12
-
13
- gem "rubocop-rspec", "~> 2.2"
14
-
15
11
  gem "rubocop-rake", "~> 0.5.1"
12
+ gem "rubocop-rspec", "~> 2.2"
13
+ gem "sqlite3", "~> 1.4"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- model_validator (1.0.0)
4
+ model_validator (1.1.0)
5
5
  rails (~> 6.1)
6
6
 
7
7
  GEM
@@ -69,13 +69,21 @@ GEM
69
69
  ast (2.4.2)
70
70
  builder (3.2.4)
71
71
  concurrent-ruby (1.1.7)
72
+ coveralls (0.8.23)
73
+ json (>= 1.8, < 3)
74
+ simplecov (~> 0.16.1)
75
+ term-ansicolor (~> 1.3)
76
+ thor (>= 0.19.4, < 2.0)
77
+ tins (~> 1.6)
72
78
  crass (1.0.6)
73
79
  diff-lcs (1.4.4)
80
+ docile (1.3.5)
74
81
  erubi (1.10.0)
75
82
  globalid (0.4.2)
76
83
  activesupport (>= 4.2.0)
77
84
  i18n (1.8.5)
78
85
  concurrent-ruby (~> 1.0)
86
+ json (2.5.1)
79
87
  loofah (2.8.0)
80
88
  crass (~> 1.0.2)
81
89
  nokogiri (>= 1.5.9)
@@ -157,6 +165,11 @@ GEM
157
165
  rubocop (~> 1.0)
158
166
  rubocop-ast (>= 1.1.0)
159
167
  ruby-progressbar (1.11.0)
168
+ simplecov (0.16.1)
169
+ docile (~> 1.1)
170
+ json (>= 1.8, < 3)
171
+ simplecov-html (~> 0.10.0)
172
+ simplecov-html (0.10.2)
160
173
  sprockets (4.0.2)
161
174
  concurrent-ruby (~> 1.0)
162
175
  rack (> 1, < 3)
@@ -165,7 +178,12 @@ GEM
165
178
  activesupport (>= 4.0)
166
179
  sprockets (>= 3.0.0)
167
180
  sqlite3 (1.4.2)
181
+ sync (0.5.0)
182
+ term-ansicolor (1.7.1)
183
+ tins (~> 1.0)
168
184
  thor (1.0.1)
185
+ tins (1.28.0)
186
+ sync
169
187
  tzinfo (2.0.3)
170
188
  concurrent-ruby (~> 1.0)
171
189
  unicode-display_width (2.0.0)
@@ -179,6 +197,7 @@ PLATFORMS
179
197
  x86_64-linux
180
198
 
181
199
  DEPENDENCIES
200
+ coveralls
182
201
  model_validator!
183
202
  rake (~> 13.0)
184
203
  rspec (~> 3.0)
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  [![Build Status](https://www.travis-ci.com/jibidus/model_validation.svg?branch=main)](https://www.travis-ci.com/jibidus/model_validation)
2
+ [![Coverage Status](https://coveralls.io/repos/github/jibidus/model_validation/badge.svg?branch=main)](https://coveralls.io/github/jibidus/model_validation?branch=main)
2
3
 
3
4
  # model_validator
4
5
 
@@ -27,10 +28,10 @@ So, because of performances reason, this is only acceptable for tiny databases (
27
28
 
28
29
  ## Installation
29
30
 
30
- Add this line to your application's Gemfile:
31
+ Add this line to your application"s Gemfile:
31
32
 
32
33
  ```ruby
33
- gem 'model_validator'
34
+ gem "model_validator"
34
35
  ```
35
36
 
36
37
  And then execute:
@@ -70,7 +71,7 @@ ModelValidator.validate_all skipped_models: [Model1,Model2]
70
71
 
71
72
  After checking out the repo, run `make install` to install dependencies.
72
73
 
73
- Then, run `make test` to run the tests.
74
+ Then, run `make test` to run the tests (test coverage is available in `coverage/index.html`).
74
75
 
75
76
  Then, run `make lint` to run linters ([rubocop](https://github.com/rubocop-hq/rubocop)).
76
77
 
@@ -78,8 +79,12 @@ To install this gem onto your local machine, run `bundle exec rake install`.
78
79
 
79
80
  ### How to release new version?
80
81
 
81
- - Update the version number in `version.rb`
82
- - 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).
82
+ Make sure your are in `main` branch. Then, run:
83
+ ```bash
84
+ rake release:make[major|minor|patch|x.y.z]
85
+ ```
86
+
87
+ Example for building a new minor release: `rake release:make[minor]`
83
88
 
84
89
  ## Why not contributing to existing gem?
85
90
 
@@ -88,7 +93,7 @@ Many already existing gems may do the same, but none are satisfying:
88
93
  - [validb](https://github.com/jgeiger/validb): depends on [sidekiq](https://github.com/mperham/sidekiq)
89
94
  - [validates_blacklist](https://www.rubydoc.info/gems/validates_blacklist/0.0.1): requires to add configuration in each model 😨
90
95
  - [valid_items](https://rubygems.org/gems/valid_items): requires rails eager load 🤔
91
- - [schema-validations](https://github.com/robworley/schema-validations): I don't understand what it really does 🤪
96
+ - [schema-validations](https://github.com/robworley/schema-validations): I don"t understand what it really does 🤪
92
97
 
93
98
  ## Contributing
94
99
 
@@ -100,4 +105,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
100
105
 
101
106
  ## Code of Conduct
102
107
 
103
- Everyone interacting in the ModelValidator project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/model_validator/blob/master/CODE_OF_CONDUCT.md).
108
+ Everyone interacting in the ModelValidator project"s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/model_validator/blob/master/CODE_OF_CONDUCT.md).
@@ -6,55 +6,81 @@ require "rails"
6
6
  module ModelValidator
7
7
  require "model_validator/railtie" if defined?(Rails)
8
8
 
9
+ # Validations summary, with:
10
+ # - violations: number of violations (i.e. number of model which validation failed)
11
+ # - total: total number of validated models
12
+ class Result
13
+ attr_accessor :violations, :total
14
+
15
+ def initialize(violations: 0, total: 0)
16
+ @violations = violations
17
+ @total = total
18
+ end
19
+ end
20
+
9
21
  def self.validate_all(skipped_models: [])
10
22
  if skipped_models.empty?
11
23
  Rails.logger.info "No model skipped"
12
24
  else
13
25
  Rails.logger.info "Skipped model(s): #{skipped_models.map(&:to_s).join(", ")}"
14
26
  end
15
- handler = LogHandler.new
16
- Validator.new(handler, skip_models: skipped_models).run
17
- handler.violations_count
27
+ stats_handler = StatsHandler.new
28
+ handlers = [LogHandler.new, stats_handler]
29
+ Validator.new(handlers: handlers, skip_models: skipped_models).run
30
+ stats_handler.result
18
31
  end
19
32
 
20
33
  # Validation engine, which fetch, and validate each database records
21
34
  class Validator
22
- def initialize(handler, skip_models: [])
23
- @handler = handler
35
+ def initialize(handlers: [], skip_models: [])
36
+ @handlers = handlers
24
37
  @skip_models = skip_models
25
38
  end
26
39
 
27
- def models_to_validate
40
+ def classes_to_validate
28
41
  ActiveRecord::Base.subclasses
29
42
  .reject { |type| type.to_s.include? "::" } # subclassed classes are not our own models
30
43
  .reject { |type| @skip_models.include? type }
31
44
  end
32
45
 
33
46
  def run
34
- models_to_validate.each do |type|
35
- @handler.start_model type
36
- type.unscoped.find_each do |record|
37
- @handler.on_violation(type, record) unless record.valid?
47
+ classes_to_validate.each do |model_class|
48
+ @handlers.each { |h| h.try(:on_new_class, model_class) }
49
+ model_class.unscoped.find_each do |model|
50
+ @handlers.each { |h| h.try(:on_violation, model) } unless model.valid?
51
+ @handlers.each { |h| h.try(:after_validation, model) }
38
52
  end
39
53
  end
40
54
  end
41
55
  end
42
56
 
43
- # Validation handler, which logs each violation
57
+ # This handler logs validation progression
44
58
  class LogHandler
45
- attr_reader :violations_count
59
+ def on_new_class(model_class)
60
+ Rails.logger.info "Checking #{model_class}..."
61
+ end
62
+
63
+ def on_violation(model)
64
+ Rails.logger.error "#<#{model.class} id: #{model.id}, errors: #{model.errors.full_messages}>" unless model.valid?
65
+ end
66
+ end
67
+
68
+ # This handler computes validation statistics
69
+ class StatsHandler
70
+ attr_reader :result
46
71
 
47
72
  def initialize
48
- @violations_count = 0
73
+ @result = Result.new(violations: 0, total: 0)
49
74
  end
50
75
 
51
- def start_model(type)
52
- Rails.logger.info "Checking #{type}..."
76
+ def on_new_class(_) end
77
+
78
+ def on_violation(_)
79
+ @result.violations += 1
53
80
  end
54
81
 
55
- def on_violation(type, record)
56
- Rails.logger.error "#<#{type} id: #{record.id}, errors: #{record.errors.full_messages}>" unless record.valid?
57
- @violations_count += 1
82
+ def after_validation(_)
83
+ @result.total += 1
58
84
  end
59
85
  end
60
86
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ModelValidator
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -8,19 +8,18 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Jibidus"]
9
9
  spec.email = ["jibidus@gmail.com"]
10
10
 
11
- spec.summary = "Validate database against Active Record model validations."
12
- spec.description = <<~FOO
13
- Many reason may make database violate Active Record validation rules
14
- (database modification without Active Record, migration…).
15
- This raises unexpected error when these records are manipulated by rails.
16
- FOO
17
- spec.homepage = "https://github.com/jibidus/model_validation"
11
+ spec.summary = "Validate database against Active Record model validations"
12
+ spec.description = <<~DESC
13
+ Find models in database which violate Active Record validation rules.
14
+ Invalid models may raise unexpected error when updated.
15
+ DESC
16
+ spec.homepage = "https://github.com/jibidus/model_validator"
18
17
  spec.license = "MIT"
19
18
  spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
20
19
 
21
20
  spec.metadata["homepage_uri"] = spec.homepage
22
- spec.metadata["source_code_uri"] = "https://github.com/jibidus/model_validation"
23
- spec.metadata["changelog_uri"] = "https://github.com/jibidus/model_validation"
21
+ spec.metadata["source_code_uri"] = "https://github.com/jibidus/model_validator"
22
+ spec.metadata["changelog_uri"] = "https://github.com/jibidus/model_validator"
24
23
 
25
24
  # Specify which files should be added to the gem when it is released.
26
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./rakelib/release/release"
4
+
5
+ namespace :release do
6
+ desc <<~DESC
7
+ Build new release.
8
+ - bump_type (mandatory): [major|minor|patch|x.y.z]
9
+ - dry_run (optional): skip commit, tag and publishing
10
+ DESC
11
+ task :make, [:bump_type, :dry_run] do |_, args|
12
+ release = Release.new args[:bump_type]
13
+ puts "Bump version from #{release.current_version} to #{release.new_version}"
14
+ release.apply!
15
+
16
+ puts
17
+ puts "#{release.new_version} changelog"
18
+ puts "---------------------------------------------------------------------"
19
+ puts release.changelog
20
+ puts "---------------------------------------------------------------------"
21
+
22
+ next if args[:dry_run]
23
+
24
+ release.git_commit!
25
+
26
+ puts <<~MSG
27
+ Release built.
28
+
29
+ Run following commands to publish version #{release.new_version}:
30
+ $> git push && git push --tags
31
+ $> bundle exec rake release
32
+
33
+ After that, do not forget to report changelog in Github Releases page:
34
+ https://github.com/jibidus/model_validator/releases
35
+ MSG
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Represents a commit in a git repository
4
+ class Commit
5
+ attr_reader :type, :message
6
+
7
+ def initialize(type, message)
8
+ @type = type
9
+ @message = message
10
+ end
11
+
12
+ def type?(types)
13
+ types.include? @type
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./rakelib/release/repository"
4
+ require "./rakelib/release/version"
5
+ require "./lib/model_validator/version"
6
+
7
+ AUTHORIZED_BRANCH = "main"
8
+
9
+ # All commit message prefix to include in changelog
10
+ COMMIT_TYPES = {
11
+ "tada" => "Feature",
12
+ "bug" => "Bug fix"
13
+ }.freeze
14
+
15
+ # This class can create and publish a new version of the current gem
16
+ class Release
17
+ GEM_NAME = "model_validator"
18
+ VERSION_FILE = "lib/model_validator/version.rb"
19
+ GEMFILE_LOCK = "Gemfile.lock"
20
+
21
+ def initialize(type)
22
+ @type = type
23
+ end
24
+
25
+ def current_version
26
+ Version.new(*ModelValidator::VERSION.split(".").map(&:to_i))
27
+ end
28
+
29
+ def new_version
30
+ @new_version ||= current_version.bump(@type)
31
+ end
32
+
33
+ def apply!
34
+ if Repository.current_branch != AUTHORIZED_BRANCH
35
+ raise <<~MSG
36
+ You can only release new version from '#{AUTHORIZED_BRANCH}' branch.
37
+ Current branch: '#{Repository.current_branch}'
38
+ MSG
39
+ end
40
+
41
+ sub_file_content VERSION_FILE, current_version.to_s, new_version.to_s
42
+ sub_file_content GEMFILE_LOCK, "#{GEM_NAME} (#{current_version})", "#{GEM_NAME} (#{new_version})"
43
+ end
44
+
45
+ def changelog
46
+ commits_by_type.map do |type, commits|
47
+ messages_list = commits.map { |commit| "- #{commit.message}\n" }.join
48
+ "# #{COMMIT_TYPES[type]}\n#{messages_list}"
49
+ end.join("\n")
50
+ end
51
+
52
+ def git_commit!
53
+ `git add #{VERSION_FILE} #{GEMFILE_LOCK}`
54
+ `git commit -m ":label: release version #{new_version}"`
55
+ end
56
+
57
+ private
58
+
59
+ def sub_file_content(file_path, from, to)
60
+ current_content = File.read(file_path)
61
+ modified_content = current_content.sub(from, to)
62
+ raise "Cannot find regexp '#{from}' in file #{file_path}" if modified_content == current_content
63
+
64
+ File.open(file_path, "w") { |file| file << modified_content }
65
+ end
66
+
67
+ def commits_by_type
68
+ Repository.commits_from(current_version)
69
+ .select { |commit| commit.type?(COMMIT_TYPES.keys) }
70
+ .group_by(&:type)
71
+ end
72
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "./rakelib/release/commit"
4
+
5
+ # This module contains many methods to manipulate current git repository
6
+ module Repository
7
+ def self.current_branch
8
+ `git rev-parse --abbrev-ref HEAD`.strip
9
+ end
10
+
11
+ def self.commits_from(tag)
12
+ logs_from("v#{tag}").sort
13
+ .uniq
14
+ .map do |commit_message|
15
+ _, type, message = commit_message.split(":", 3).map(&:strip)
16
+ if message.nil?
17
+ message = type
18
+ type = "unknown"
19
+ end
20
+ Commit.new(type, message)
21
+ end
22
+ end
23
+
24
+ def self.logs_from(revision)
25
+ `git log #{revision}..HEAD --pretty=format:"%s"`.split("\n")
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Represent a gem version, which can be bumped for new release.
4
+ class Version
5
+ def initialize(major, minor, patch)
6
+ @major = major
7
+ @minor = minor
8
+ @patch = patch
9
+ end
10
+
11
+ def bump(release_type)
12
+ case release_type
13
+ when "major"
14
+ Version.new(@major + 1, 0, 0)
15
+ when "minor"
16
+ Version.new(@major, @minor + 1, 0)
17
+ when "patch"
18
+ Version.new(@major, @minor, @patch + 1)
19
+ else
20
+ raise "Unknonwn bump type '#{release_type}'"
21
+ end
22
+ end
23
+
24
+ def to_s
25
+ [@major, @minor, @patch].join(".")
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: model_validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jibidus
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-14 00:00:00.000000000 Z
11
+ date: 2021-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -25,9 +25,8 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '6.1'
27
27
  description: |
28
- Many reason may make database violate Active Record validation rules
29
- (database modification without Active Record, migration…).
30
- This raises unexpected error when these records are manipulated by rails.
28
+ Find models in database which violate Active Record validation rules.
29
+ Invalid models may raise unexpected error when updated.
31
30
  email:
32
31
  - jibidus@gmail.com
33
32
  executables: []
@@ -45,21 +44,24 @@ files:
45
44
  - Makefile
46
45
  - README.md
47
46
  - Rakefile
48
- - bin/console
49
- - bin/setup
50
47
  - lib/model_validator.rb
51
48
  - lib/model_validator/Rakefile
52
49
  - lib/model_validator/railtie.rb
53
50
  - lib/model_validator/tasks/db/validate.rake
54
51
  - lib/model_validator/version.rb
55
52
  - model_validator.gemspec
56
- homepage: https://github.com/jibidus/model_validation
53
+ - rakelib/release.rake
54
+ - rakelib/release/commit.rb
55
+ - rakelib/release/release.rb
56
+ - rakelib/release/repository.rb
57
+ - rakelib/release/version.rb
58
+ homepage: https://github.com/jibidus/model_validator
57
59
  licenses:
58
60
  - MIT
59
61
  metadata:
60
- homepage_uri: https://github.com/jibidus/model_validation
61
- source_code_uri: https://github.com/jibidus/model_validation
62
- changelog_uri: https://github.com/jibidus/model_validation
62
+ homepage_uri: https://github.com/jibidus/model_validator
63
+ source_code_uri: https://github.com/jibidus/model_validator
64
+ changelog_uri: https://github.com/jibidus/model_validator
63
65
  post_install_message:
64
66
  rdoc_options: []
65
67
  require_paths:
@@ -78,5 +80,5 @@ requirements: []
78
80
  rubygems_version: 3.1.4
79
81
  signing_key:
80
82
  specification_version: 4
81
- summary: Validate database against Active Record model validations.
83
+ summary: Validate database against Active Record model validations
82
84
  test_files: []
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "bundler/setup"
5
- require "model_validator"
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require "irb"
15
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here