rubocop-minitest 0.15.1 → 0.17.1

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +9 -9
  3. data/.github/PULL_REQUEST_TEMPLATE.md +3 -4
  4. data/.github/workflows/spell_checking.yml +33 -0
  5. data/.rubocop.yml +2 -3
  6. data/.rubocop_todo.yml +2 -0
  7. data/.yardopts +3 -0
  8. data/CHANGELOG.md +30 -0
  9. data/CONTRIBUTING.md +3 -2
  10. data/Gemfile +4 -1
  11. data/LICENSE.txt +1 -1
  12. data/Rakefile +4 -6
  13. data/codespell.txt +0 -0
  14. data/config/default.yml +13 -2
  15. data/docs/antora.yml +1 -1
  16. data/docs/modules/ROOT/pages/cops_minitest.adoc +99 -4
  17. data/docs/modules/ROOT/pages/installation.adoc +1 -1
  18. data/lib/rubocop/cop/minitest/assert_empty.rb +12 -0
  19. data/lib/rubocop/cop/minitest/assert_empty_literal.rb +1 -1
  20. data/lib/rubocop/cop/minitest/assert_with_expected_argument.rb +3 -2
  21. data/lib/rubocop/cop/minitest/assertion_in_lifecycle_hook.rb +1 -1
  22. data/lib/rubocop/cop/minitest/global_expectations.rb +109 -38
  23. data/lib/rubocop/cop/minitest/multiple_assertions.rb +1 -1
  24. data/lib/rubocop/cop/minitest/no_assertions.rb +1 -1
  25. data/lib/rubocop/cop/minitest/refute_empty.rb +12 -0
  26. data/lib/rubocop/cop/minitest/unreachable_assertion.rb +2 -4
  27. data/lib/rubocop/cop/mixin/minitest_exploration_helpers.rb +9 -21
  28. data/lib/rubocop/minitest/assert_offense.rb +183 -0
  29. data/lib/rubocop/minitest/support.rb +10 -0
  30. data/lib/rubocop/minitest/version.rb +1 -1
  31. data/mkdocs.yml +1 -1
  32. data/relnotes/v0.15.2.md +5 -0
  33. data/relnotes/v0.16.0.md +11 -0
  34. data/relnotes/v0.17.0.md +5 -0
  35. data/relnotes/v0.17.1.md +5 -0
  36. data/rubocop-minitest.gemspec +2 -1
  37. data/tasks/changelog.rake +34 -0
  38. data/tasks/changelog.rb +166 -0
  39. data/tasks/cops_documentation.rake +5 -15
  40. data/tasks/cut_release.rake +19 -4
  41. metadata +16 -4
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ if RUBY_VERSION < '2.6'
4
+ puts 'Changelog utilities available only for Ruby 2.6+'
5
+ exit(1)
6
+ end
7
+
8
+ # Changelog utility
9
+ class Changelog
10
+ ENTRIES_PATH = 'changelog/'
11
+ FIRST_HEADER = /#{Regexp.escape("## master (unreleased)\n")}/m.freeze
12
+ ENTRIES_PATH_TEMPLATE = "#{ENTRIES_PATH}%<type>s_%<name>s.md"
13
+ TYPE_REGEXP = /#{Regexp.escape(ENTRIES_PATH)}([a-z]+)_/.freeze
14
+ TYPE_TO_HEADER = { new: 'New features', fix: 'Bug fixes', change: 'Changes' }.freeze
15
+ HEADER = /### (.*)/.freeze
16
+ PATH = 'CHANGELOG.md'
17
+ REF_URL = 'https://github.com/rubocop/rubocop-minitest'
18
+ MAX_LENGTH = 40
19
+ CONTRIBUTOR = '[@%<user>s]: https://github.com/%<user>s'
20
+ SIGNATURE = Regexp.new(format(Regexp.escape('[@%<user>s][]'), user: '([\w-]+)'))
21
+ EOF = "\n"
22
+
23
+ # New entry
24
+ Entry = Struct.new(:type, :body, :ref_type, :ref_id, :user, keyword_init: true) do
25
+ def initialize(type:, body: last_commit_title, ref_type: nil, ref_id: nil, user: github_user)
26
+ id, body = extract_id(body)
27
+ ref_id ||= id || 'x'
28
+ ref_type ||= id ? :issues : :pull
29
+ super
30
+ end
31
+
32
+ def write
33
+ Dir.mkdir(ENTRIES_PATH) unless Dir.exist?(ENTRIES_PATH)
34
+ File.write(path, content)
35
+ path
36
+ end
37
+
38
+ def path
39
+ format(ENTRIES_PATH_TEMPLATE, type: type, name: str_to_filename(body))
40
+ end
41
+
42
+ def content
43
+ period = '.' unless body.end_with? '.'
44
+ "* #{ref}: #{body}#{period} ([@#{user}][])\n"
45
+ end
46
+
47
+ def ref
48
+ "[##{ref_id}](#{REF_URL}/#{ref_type}/#{ref_id})"
49
+ end
50
+
51
+ def last_commit_title
52
+ `git log -1 --pretty=%B`.lines.first.chomp
53
+ end
54
+
55
+ def extract_id(body)
56
+ /^\[Fix(?:es)? #(\d+)\] (.*)/.match(body)&.captures || [nil, body]
57
+ end
58
+
59
+ def str_to_filename(str)
60
+ str
61
+ .downcase
62
+ .split
63
+ .each { |s| s.gsub!(/\W/, '') }
64
+ .reject(&:empty?)
65
+ .inject do |result, word|
66
+ s = "#{result}_#{word}"
67
+ return result if s.length > MAX_LENGTH
68
+
69
+ s
70
+ end
71
+ end
72
+
73
+ def github_user
74
+ user = `git config --global credential.username`.chomp
75
+ warn 'Set your username with `git config --global credential.username "myusernamehere"`' if user.empty?
76
+
77
+ user
78
+ end
79
+ end
80
+ attr_reader :header, :rest
81
+
82
+ def initialize(content: File.read(PATH), entries: Changelog.read_entries)
83
+ require 'strscan'
84
+
85
+ parse(content)
86
+ @entries = entries
87
+ end
88
+
89
+ def and_delete!
90
+ @entries.each_key { |path| File.delete(path) }
91
+ end
92
+
93
+ def merge!
94
+ File.write(PATH, merge_content)
95
+ self
96
+ end
97
+
98
+ def unreleased_content
99
+ entry_map = parse_entries(@entries)
100
+ merged_map = merge_entries(entry_map)
101
+ merged_map.flat_map { |header, things| ["### #{header}\n", *things, ''] }.join("\n")
102
+ end
103
+
104
+ def merge_content
105
+ merged_content = [@header, unreleased_content, @rest.chomp, *new_contributor_lines].join("\n")
106
+
107
+ merged_content << EOF
108
+ end
109
+
110
+ def self.pending?
111
+ entry_paths.any?
112
+ end
113
+
114
+ def self.entry_paths
115
+ Dir["#{ENTRIES_PATH}*"]
116
+ end
117
+
118
+ def self.read_entries
119
+ entry_paths.to_h { |path| [path, File.read(path)] }
120
+ end
121
+
122
+ def new_contributor_lines
123
+ contributors
124
+ .map { |user| format(CONTRIBUTOR, user: user) }
125
+ .reject { |line| @rest.include?(line) }
126
+ end
127
+
128
+ def contributors
129
+ contributors = @entries.values.flat_map do |entry|
130
+ entry.match(/\. \((?<contributors>.+)\)\n/)[:contributors].split(',')
131
+ end
132
+
133
+ contributors.join.scan(SIGNATURE).flatten
134
+ end
135
+
136
+ private
137
+
138
+ def merge_entries(entry_map)
139
+ all = @unreleased.merge(entry_map) { |_k, v1, v2| v1.concat(v2) }
140
+ canonical = TYPE_TO_HEADER.values.to_h { |v| [v, nil] }
141
+ canonical.merge(all).compact
142
+ end
143
+
144
+ def parse(content)
145
+ ss = StringScanner.new(content)
146
+ @header = ss.scan_until(FIRST_HEADER)
147
+ @unreleased = parse_release(ss.scan_until(/\n(?=## )/m))
148
+ @rest = ss.rest
149
+ end
150
+
151
+ # @return [Hash<type, Array<String>]]
152
+ def parse_release(unreleased)
153
+ unreleased.lines.map(&:chomp).reject(&:empty?).slice_before(HEADER).to_h do |header, *entries|
154
+ [HEADER.match(header)[1], entries]
155
+ end
156
+ end
157
+
158
+ def parse_entries(path_content_map)
159
+ changes = Hash.new { |h, k| h[k] = [] }
160
+ path_content_map.each do |path, content|
161
+ header = TYPE_TO_HEADER.fetch(TYPE_REGEXP.match(path)[1].to_sym)
162
+ changes[header].concat(content.lines.map(&:chomp))
163
+ end
164
+ changes
165
+ end
166
+ end
@@ -10,24 +10,14 @@ YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
10
10
  task.options = ['--no-output']
11
11
  end
12
12
 
13
- desc 'Generate docs of all cops departments'
14
- task generate_cops_documentation: :yard_for_generate_documentation do
13
+ task update_cops_documentation: :yard_for_generate_documentation do
15
14
  deps = ['Minitest']
16
- CopsDocumentationGenerator.new(departments: deps).call
17
- end
18
-
19
- desc 'Verify that documentation is up to date'
20
- task verify_cops_documentation: :generate_cops_documentation do
21
- # Do not print diff and yield whether exit code was zero
22
- sh('git diff --quiet docs') do |outcome, _|
23
- exit if outcome
24
15
 
25
- # Output diff before raising error
26
- sh('GIT_PAGER=cat git diff docs')
16
+ # NOTE: Update `<<next>>` version for docs/modules/ROOT/pages/cops_minitest.adoc
17
+ # when running release tasks.
18
+ RuboCop::Minitest::Inject.defaults!
27
19
 
28
- warn 'The docs directory is out of sync. Run `rake generate_cops_documentation` and commit the results.'
29
- exit!
30
- end
20
+ CopsDocumentationGenerator.new(departments: deps).call
31
21
  end
32
22
 
33
23
  desc 'Syntax check for the documentation comments'
@@ -4,9 +4,8 @@ require 'bump'
4
4
 
5
5
  namespace :cut_release do
6
6
  %w[major minor patch pre].each do |release_type|
7
- desc "Cut a new #{release_type} release, create release notes " \
8
- 'and update documents.'
9
- task release_type do
7
+ desc "Cut a new #{release_type} release, create release notes and update documents."
8
+ task release_type => 'changelog:check_clean' do
10
9
  run(release_type)
11
10
  end
12
11
  end
@@ -40,7 +39,7 @@ namespace :cut_release do
40
39
 
41
40
  File.open('docs/antora.yml', 'w') do |f|
42
41
  f << antora_metadata.sub(
43
- 'version: master',
42
+ "version: 'master'",
44
43
  "version: '#{version_sans_patch(new_version)}'"
45
44
  )
46
45
  end
@@ -50,12 +49,25 @@ namespace :cut_release do
50
49
  version.split('.').take(2).join('.')
51
50
  end
52
51
 
52
+ # Replace `<<next>>` (and variations) with version being cut.
53
+ def update_cop_versions(_old_version, new_version)
54
+ update_file('config/default.yml') do |default|
55
+ default.gsub(/['"]?<<\s*next\s*>>['"]?/i,
56
+ "'#{version_sans_patch(new_version)}'")
57
+ end
58
+ end
59
+
53
60
  def new_version_changes
54
61
  changelog = File.read('CHANGELOG.md')
55
62
  _, _, new_changes, _older_changes = changelog.split(/^## .*$/, 4)
56
63
  new_changes
57
64
  end
58
65
 
66
+ def update_file(path)
67
+ content = File.read(path)
68
+ File.write(path, yield(content))
69
+ end
70
+
59
71
  def user_links(text)
60
72
  names = text.scan(/\[@(\S+)\]\[\]/).map(&:first).uniq
61
73
  names.map { |name| "[@#{name}]: https://github.com/#{name}" }
@@ -67,6 +79,9 @@ namespace :cut_release do
67
79
  Bump::Bump.run(release_type, commit: false, bundle: false, tag: false)
68
80
  new_version = Bump::Bump.current
69
81
 
82
+ update_cop_versions(old_version, new_version)
83
+ Rake::Task['update_cops_documentation'].invoke
84
+
70
85
  add_header_to_changelog(new_version)
71
86
  create_release_notes(new_version)
72
87
  update_antora_yml(new_version)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-minitest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-09-26 00:00:00.000000000 Z
13
+ date: 2022-01-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -60,9 +60,11 @@ files:
60
60
  - ".github/ISSUE_TEMPLATE/bug_report.md"
61
61
  - ".github/ISSUE_TEMPLATE/feature_request.md"
62
62
  - ".github/PULL_REQUEST_TEMPLATE.md"
63
+ - ".github/workflows/spell_checking.yml"
63
64
  - ".gitignore"
64
65
  - ".rubocop.yml"
65
66
  - ".rubocop_todo.yml"
67
+ - ".yardopts"
66
68
  - CHANGELOG.md
67
69
  - CONTRIBUTING.md
68
70
  - Gemfile
@@ -71,6 +73,7 @@ files:
71
73
  - Rakefile
72
74
  - bin/console
73
75
  - bin/setup
76
+ - codespell.txt
74
77
  - config/default.yml
75
78
  - docs/antora.yml
76
79
  - docs/modules/ROOT/nav.adoc
@@ -127,7 +130,9 @@ files:
127
130
  - lib/rubocop/cop/mixin/minitest_exploration_helpers.rb
128
131
  - lib/rubocop/cop/mixin/nil_assertion_handleable.rb
129
132
  - lib/rubocop/minitest.rb
133
+ - lib/rubocop/minitest/assert_offense.rb
130
134
  - lib/rubocop/minitest/inject.rb
135
+ - lib/rubocop/minitest/support.rb
131
136
  - lib/rubocop/minitest/version.rb
132
137
  - mkdocs.yml
133
138
  - readthedocs.yml
@@ -144,6 +149,10 @@ files:
144
149
  - relnotes/v0.14.0.md
145
150
  - relnotes/v0.15.0.md
146
151
  - relnotes/v0.15.1.md
152
+ - relnotes/v0.15.2.md
153
+ - relnotes/v0.16.0.md
154
+ - relnotes/v0.17.0.md
155
+ - relnotes/v0.17.1.md
147
156
  - relnotes/v0.2.0.md
148
157
  - relnotes/v0.2.1.md
149
158
  - relnotes/v0.3.0.md
@@ -159,6 +168,8 @@ files:
159
168
  - relnotes/v0.8.1.md
160
169
  - relnotes/v0.9.0.md
161
170
  - rubocop-minitest.gemspec
171
+ - tasks/changelog.rake
172
+ - tasks/changelog.rb
162
173
  - tasks/cops_documentation.rake
163
174
  - tasks/cut_release.rake
164
175
  homepage:
@@ -168,8 +179,9 @@ metadata:
168
179
  homepage_uri: https://docs.rubocop.org/rubocop-minitest/
169
180
  changelog_uri: https://github.com/rubocop/rubocop-minitest/blob/master/CHANGELOG.md
170
181
  source_code_uri: https://github.com/rubocop/rubocop-minitest
171
- documentation_uri: https://docs.rubocop.org/rubocop-minitest/0.15
182
+ documentation_uri: https://docs.rubocop.org/rubocop-minitest/0.17
172
183
  bug_tracker_uri: https://github.com/rubocop/rubocop-minitest/issues
184
+ rubygems_mfa_required: 'true'
173
185
  post_install_message:
174
186
  rdoc_options: []
175
187
  require_paths:
@@ -185,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
197
  - !ruby/object:Gem::Version
186
198
  version: '0'
187
199
  requirements: []
188
- rubygems_version: 3.3.0.dev
200
+ rubygems_version: 3.3.3
189
201
  signing_key:
190
202
  specification_version: 4
191
203
  summary: Automatic Minitest code style checking tool.