pronto-rails_migrations_annotated 0.0.2 → 0.0.3
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/.rubocop.yml +19 -1
- data/Gemfile +3 -0
- data/Gemfile.lock +11 -1
- data/README.md +2 -5
- data/lib/pronto/rails_migrations_annotated/version.rb +1 -1
- data/lib/pronto/rails_migrations_annotated.rb +135 -94
- data/pronto-rails_migrations_annotated.gemspec +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88430fc4dc1457f81ee58ddbb791363370cb6e85fcd6ffe17b504717a637d5de
|
4
|
+
data.tar.gz: e7f1c20a1f124f27506cb1494d756d1ab314cd9217ce075e68e7a42842380030
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f56e324b56c92ef3e2957bd39a6dba969e6fa4748bf8acadc1e077288cf0abb882b6e30b9c7c1f9a6d4d0a73b2be713a344e66c8c2d5aee667e7e6dd379f21d
|
7
|
+
data.tar.gz: a9f3ebffd0dd50bc1549d669069cc27a0f3cd67dc0064d428c03f1adffcd0d58df885485e4b9458dbb0c95a8a244e4dc479fbffbb7b2ea169742a73e7b7db5ad
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rake
|
3
|
+
- rubocop-rspec
|
4
|
+
- rubocop-performance
|
5
|
+
|
1
6
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
7
|
+
TargetRubyVersion: 2.5
|
8
|
+
NewCops: enable
|
9
|
+
Exclude:
|
10
|
+
- spec/fixtures/somerepo/**/*.rb
|
3
11
|
|
4
12
|
Style/StringLiterals:
|
5
13
|
Enabled: true
|
@@ -11,3 +19,13 @@ Style/StringLiteralsInInterpolation:
|
|
11
19
|
|
12
20
|
Layout/LineLength:
|
13
21
|
Max: 120
|
22
|
+
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Exclude:
|
25
|
+
- spec/**/*.rb
|
26
|
+
Metrics/ClassLength:
|
27
|
+
Max: 180
|
28
|
+
Metrics/AbcSize:
|
29
|
+
Max: 25
|
30
|
+
Metrics/CyclomaticComplexity:
|
31
|
+
Max: 8
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pronto-rails_migrations_annotated (0.0.
|
4
|
+
pronto-rails_migrations_annotated (0.0.3)
|
5
5
|
pronto (~> 0.11)
|
6
6
|
|
7
7
|
GEM
|
@@ -84,6 +84,13 @@ GEM
|
|
84
84
|
unicode-display_width (>= 1.4.0, < 3.0)
|
85
85
|
rubocop-ast (1.13.0)
|
86
86
|
parser (>= 3.0.1.1)
|
87
|
+
rubocop-performance (1.12.0)
|
88
|
+
rubocop (>= 1.7.0, < 2.0)
|
89
|
+
rubocop-ast (>= 0.4.0)
|
90
|
+
rubocop-rake (0.6.0)
|
91
|
+
rubocop (~> 1.0)
|
92
|
+
rubocop-rspec (2.6.0)
|
93
|
+
rubocop (~> 1.19)
|
87
94
|
ruby-progressbar (1.11.0)
|
88
95
|
ruby2_keywords (0.0.5)
|
89
96
|
rugged (1.0.1)
|
@@ -103,6 +110,9 @@ DEPENDENCIES
|
|
103
110
|
rake (~> 13.0)
|
104
111
|
rspec (~> 3.0)
|
105
112
|
rubocop (~> 1.21)
|
113
|
+
rubocop-performance
|
114
|
+
rubocop-rake
|
115
|
+
rubocop-rspec
|
106
116
|
|
107
117
|
BUNDLED WITH
|
108
118
|
2.2.31
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# Pronto::RailsMigrationsAnnotated
|
2
|
+
[](https://badge.fury.io/rb/pronto-rails_migrations_annotated)
|
2
3
|
|
3
4
|
Pronto runner to enforce migrations to be in separate PRs, but allow schema annotations.
|
4
5
|
Also check for obvious things like adding migration number that is not present in PR to structure.sql.
|
@@ -8,17 +9,13 @@ Also check for obvious things like adding migration number that is not present i
|
|
8
9
|
Add this line to your application's Gemfile:
|
9
10
|
|
10
11
|
```ruby
|
11
|
-
gem 'pronto-rails_migrations_annotated'
|
12
|
+
gem 'pronto-rails_migrations_annotated', require: false
|
12
13
|
```
|
13
14
|
|
14
15
|
And then execute:
|
15
16
|
|
16
17
|
$ bundle install
|
17
18
|
|
18
|
-
Or install it yourself as:
|
19
|
-
|
20
|
-
$ gem install pronto-rails_migrations_annotated
|
21
|
-
|
22
19
|
## Usage
|
23
20
|
|
24
21
|
When in gemfile - pronto should pick up this runner automatically.
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "pronto"
|
4
4
|
require_relative "rails_migrations_annotated/version"
|
5
5
|
|
6
6
|
module Pronto
|
7
|
+
# Runner that detects migration smells
|
7
8
|
class RailsMigrationsAnnotated < Runner
|
8
9
|
VERSION = Pronto::RailsMigrationsAnnotatedVersion::VERSION
|
9
10
|
|
@@ -11,13 +12,15 @@ module Pronto
|
|
11
12
|
@messages = []
|
12
13
|
|
13
14
|
check_migrations_mixed_with_code
|
14
|
-
|
15
|
+
check_migration_schema_version
|
16
|
+
check_structure_migration_version_numbers
|
15
17
|
check_large_schema_diff
|
18
|
+
check_large_structure_diff
|
16
19
|
|
17
20
|
@messages
|
18
21
|
end
|
19
22
|
|
20
|
-
#
|
23
|
+
# TODO: override def self.title ?
|
21
24
|
|
22
25
|
private
|
23
26
|
|
@@ -25,19 +28,11 @@ module Pronto
|
|
25
28
|
patches = [patches] unless patches.is_a?(Array)
|
26
29
|
patches.each do |patch|
|
27
30
|
target_line = case line
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@messages << Message.new(
|
34
|
-
patch.delta.new_file[:path],
|
35
|
-
target_line,
|
36
|
-
level,
|
37
|
-
message,
|
38
|
-
nil,
|
39
|
-
self.class
|
40
|
-
)
|
31
|
+
when :first then patch.added_lines.first || patch.lines.first
|
32
|
+
when :last then patch.added_lines.last || patch.lines.last
|
33
|
+
else line
|
34
|
+
end
|
35
|
+
@messages << Message.new(patch.delta.new_file[:path], target_line, level, message, nil, self.class)
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
@@ -48,14 +43,18 @@ module Pronto
|
|
48
43
|
|
49
44
|
def check_large_schema_diff
|
50
45
|
return unless diff_threshold
|
46
|
+
return unless schema_patches.sum(&:additions) >= diff_threshold ||
|
47
|
+
schema_patches.sum(&:deletions) >= diff_threshold
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
end
|
49
|
+
add_message_at_patch(schema_patches.first, "Large schema diff, pay attention")
|
50
|
+
end
|
55
51
|
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
def check_large_structure_diff
|
53
|
+
return unless diff_threshold
|
54
|
+
return unless structure_patches.sum(&:additions) >= diff_threshold ||
|
55
|
+
structure_patches.sum(&:deletions) >= diff_threshold
|
56
|
+
|
57
|
+
add_message_at_patch(structure_patches.first, "Large structure diff, pay attention")
|
59
58
|
end
|
60
59
|
|
61
60
|
def check_migrations_mixed_with_code
|
@@ -64,82 +63,109 @@ module Pronto
|
|
64
63
|
add_message_at_patch(migration_patches, "Do not mix migrations with other stuff", :fatal)
|
65
64
|
end
|
66
65
|
|
67
|
-
def
|
68
|
-
return
|
66
|
+
def check_migration_schema_version
|
67
|
+
return if migration_patches.none? || !File.exist?(schema_file_name) || gitignored?(schema_file_name)
|
69
68
|
|
70
|
-
|
71
|
-
|
72
|
-
schema_file_name = 'db/schema.rb'
|
73
|
-
if File.exist?(schema_file_name) && !gitignored?(schema_file_name)
|
74
|
-
if schema_patches.none?
|
75
|
-
add_message_at_patch(migration_patches, "Migration file detected, but no changes in schema.rb", :error)
|
76
|
-
else
|
77
|
-
match = File.read(schema_file_name).match(%r{ActiveRecord::Schema.define\(version:\s*(?<version>[0-9_]+)\s*\)})
|
78
|
-
if match
|
79
|
-
schema_migration_version = match[:version]
|
80
|
-
schema_migration_version_clean = schema_migration_version.gsub(/[^0-9]/, '')
|
81
|
-
version_numbers.select { |version| version > schema_migration_version_clean }.each do |wrong_version|
|
82
|
-
add_message_at_patch(
|
83
|
-
migration_patches.first { |patch| patch.delta.new_file[:path].include?(wrong_version) },
|
84
|
-
"Migration version #{wrong_version} is above schema.rb version #{schema_migration_version}"
|
85
|
-
)
|
86
|
-
end
|
87
|
-
else
|
88
|
-
add_message_at_patch(migration_patches.first, "Cannot detect schema migration version", :warning)
|
89
|
-
end
|
90
|
-
end
|
69
|
+
if schema_patches.none?
|
70
|
+
return add_message_at_patch(migration_patches, "Migration file detected, but no changes in schema.rb", :error)
|
91
71
|
end
|
92
72
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
version_numbers.select { |version| versions_from_schema.none? { |strct_ver| strct_ver.include?(version) } }
|
101
|
-
.each do |wrong_version|
|
102
|
-
missing_from_structure = true
|
103
|
-
add_message_at_patch(
|
104
|
-
migration_patches.first { |patch| patch.delta.new_file[:path].include?(wrong_version) },
|
105
|
-
"Migration #{wrong_version} is missing from structure.sql", :error
|
106
|
-
)
|
107
|
-
end
|
73
|
+
migration_version_numbers.select { |version| schema_migration_version&.<(version) }.each do |wrong_version|
|
74
|
+
add_message_at_patch(
|
75
|
+
migration_patches.first { |patch| patch.delta.new_file[:path].include?(wrong_version) },
|
76
|
+
"Migration version #{wrong_version} is above schema.rb version #{schema_migration_version}"
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
108
80
|
|
109
|
-
|
110
|
-
|
111
|
-
end
|
81
|
+
def schema_migration_version
|
82
|
+
return @schema_migration_version if defined? @schema_migration_version
|
112
83
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
84
|
+
@schema_migration_version ||= File.read(schema_file_name)
|
85
|
+
.match(/ActiveRecord::Schema.define\(version:\s*(?<version>[0-9_]+)\s*\)/)
|
86
|
+
&.[](:version)&.gsub(/[^0-9]/, "") ||
|
87
|
+
(add_message_at_patch(migration_patches.first,
|
88
|
+
"Cannot detect migration version in schema.rb. "\
|
89
|
+
"Migration versions are not checked.",
|
90
|
+
:warning) && nil)
|
91
|
+
end
|
120
92
|
|
121
|
-
|
122
|
-
|
123
|
-
|
93
|
+
def migration_version_numbers
|
94
|
+
@migration_version_numbers ||= migration_patches.map do |patch|
|
95
|
+
patch.delta.new_file[:path].sub(/^[^0-9]*([0-9]+).+/, '\1')
|
96
|
+
end
|
97
|
+
end
|
124
98
|
|
125
|
-
|
126
|
-
|
99
|
+
def check_structure_migration_version_numbers
|
100
|
+
return unless migration_patches.any?
|
127
101
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
102
|
+
structure_file_name = "db/structure.sql"
|
103
|
+
return if !File.exist?(structure_file_name) || gitignored?(structure_file_name)
|
104
|
+
|
105
|
+
structure_file_lines = File.readlines(structure_file_name)
|
106
|
+
versions_from_schema = structure_file_lines.grep(migration_line_regex)
|
107
|
+
|
108
|
+
check_structure_versions_present(versions_from_schema)
|
109
|
+
check_structure_migration_missing
|
110
|
+
|
111
|
+
check_structure_versions_syntax(versions_from_schema)
|
112
|
+
check_structure_versions_sorted(versions_from_schema)
|
113
|
+
check_structure_ending(structure_file_lines)
|
114
|
+
end
|
115
|
+
|
116
|
+
def check_structure_versions_present(versions_from_schema)
|
117
|
+
found_missing_migration = false
|
118
|
+
migration_version_numbers.select { |version| versions_from_schema.none? { |ver| ver.include?(version) } }
|
119
|
+
.each do |wrong_version|
|
120
|
+
found_missing_migration = true
|
121
|
+
add_message_at_patch(migration_patches.first { |patch| patch.delta.new_file[:path].include?(wrong_version) },
|
122
|
+
"Migration #{wrong_version} is missing from structure.sql", :error)
|
123
|
+
end
|
124
|
+
|
125
|
+
return if structure_patches.any? || found_missing_migration
|
126
|
+
|
127
|
+
add_message_at_patch(migration_patches, "Migration file detected, but no changes in structure.sql")
|
128
|
+
end
|
134
129
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
130
|
+
def check_structure_migration_missing
|
131
|
+
structure_patches.each do |patch|
|
132
|
+
patch.added_lines.select { |line| line.content.match?(migration_line_regex) }.each do |line|
|
133
|
+
version = line.content.match(migration_line_regex)[:version]
|
134
|
+
next if migration_version_numbers.include?(version)
|
135
|
+
next if line.content.end_with?(",") &&
|
136
|
+
patch.deleted_lines.any? { |del| del.content.include?("#{version}');") }
|
137
|
+
|
138
|
+
add_message_at_patch(patch, "Migration #{version} is not present in this changeset", :error, line: line)
|
140
139
|
end
|
141
140
|
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def check_structure_versions_sorted(versions_from_schema)
|
144
|
+
return if versions_from_schema == versions_from_schema.sort
|
145
|
+
|
146
|
+
add_message_at_patch(
|
147
|
+
structure_patches.first { |patch| patch.lines.any? { |line| line.content.match?(migration_line_regex) } },
|
148
|
+
"Migration versions must be sorted and have correct syntax"
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
def check_structure_versions_syntax(versions_from_schema)
|
153
|
+
return if versions_from_schema.last.end_with?("');\n") &&
|
154
|
+
versions_from_schema.all? { |line| line.end_with?("'),\n", "');\n") }
|
142
155
|
|
156
|
+
add_message_at_patch(
|
157
|
+
structure_patches.first { |patch| patch.lines.any? { |line| line.content.match?(migration_line_regex) } },
|
158
|
+
"Migration version lines must be separated by comma and end with semicolon"
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def check_structure_ending(structure_file_lines)
|
163
|
+
return if structure_patches.none?
|
164
|
+
return if structure_file_lines.last(2) == %W[\n \n] && structure_file_lines[-3] != "\n"
|
165
|
+
return if structure_file_lines.last.match?(/\A\s*[^\s]+\s*\n/)
|
166
|
+
|
167
|
+
add_message_at_patch(structure_patches.last,
|
168
|
+
"structure.sql must end with a newline or 2 empty lines", line: :last)
|
143
169
|
end
|
144
170
|
|
145
171
|
def gitignored?(path)
|
@@ -149,6 +175,22 @@ module Pronto
|
|
149
175
|
nil
|
150
176
|
end
|
151
177
|
|
178
|
+
def schema_file_name
|
179
|
+
"db/schema.rb"
|
180
|
+
end
|
181
|
+
|
182
|
+
def migration_line_regex
|
183
|
+
/\A\s*\('(?<version>[0-9]{14})'\)/
|
184
|
+
end
|
185
|
+
|
186
|
+
def migration_related_files
|
187
|
+
Regexp.union(
|
188
|
+
%r{db/migrate/.*[0-9]+_\w+.rb},
|
189
|
+
%r{db/schema.rb},
|
190
|
+
%r{db/structure.sql}
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
152
194
|
def migration_patches
|
153
195
|
# nb: there may be engines added to migrations_paths in config or database.yml
|
154
196
|
# but cannot check for this without more knowledge into the particular app
|
@@ -159,14 +201,14 @@ module Pronto
|
|
159
201
|
end
|
160
202
|
|
161
203
|
def non_migration_related_patches
|
162
|
-
@patches.
|
204
|
+
@patches.select do |patch|
|
163
205
|
path = patch.delta.new_file[:path]
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
206
|
+
next false if path.match?(migration_related_files)
|
207
|
+
|
208
|
+
# allow edits in comments and blank lines (model annotations usually come there)
|
209
|
+
!path.end_with?(".rb") || patch.lines.any? do |line|
|
210
|
+
(line.addition? || line.deletion?) && !line.content.match?(/\A\s*(#|\z)/)
|
211
|
+
end
|
170
212
|
end
|
171
213
|
end
|
172
214
|
|
@@ -177,6 +219,5 @@ module Pronto
|
|
177
219
|
def structure_patches
|
178
220
|
@structure_patches = @patches.select { |patch| patch.delta.new_file[:path] =~ %r{db/structure.sql} }
|
179
221
|
end
|
180
|
-
|
181
222
|
end
|
182
223
|
end
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
TEXT
|
16
16
|
spec.homepage = "https://github.com/Vasfed/pronto-rails_migrations_annotated"
|
17
17
|
spec.license = "MIT"
|
18
|
-
spec.required_ruby_version = ">= 2.
|
18
|
+
spec.required_ruby_version = ">= 2.5.0"
|
19
19
|
|
20
20
|
spec.metadata["homepage_uri"] = spec.homepage
|
21
21
|
spec.metadata["source_code_uri"] = "https://github.com/Vasfed/pronto-rails_migrations_annotated"
|
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
|
|
30
30
|
end
|
31
31
|
spec.require_paths = ["lib"]
|
32
32
|
|
33
|
-
spec.add_dependency "pronto",
|
33
|
+
spec.add_dependency "pronto", "~>0.11"
|
34
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pronto-rails_migrations_annotated
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vasily Fedoseyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pronto
|
@@ -57,7 +57,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 2.
|
60
|
+
version: 2.5.0
|
61
61
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
62
|
requirements:
|
63
63
|
- - ">="
|