rubocop-committee 0.1.1 → 1.0.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: 41386b965b9dd62eb7c3bc00d39a20547f7aa06d0b2efe2aaa4186512310b089
4
- data.tar.gz: 437cb3e7a79d44bef6d04739b561d1a0cd28bc924474ec0d8b05863fdc16d954
3
+ metadata.gz: ff90da55bb78b45d0022371df0b3a2f0cd6d54c7c0714f79cb95f7878e34d285
4
+ data.tar.gz: d19b4f2aa1c16ae1de412f1ed7ba076a578f936a624334e7c80ed9a728ee5e59
5
5
  SHA512:
6
- metadata.gz: dd861b26292413e85655a365f709ac7af88fbad73118ce91992ba7a86eecb245d3f960d5d78a46b64a1ded70c669f56b8c445397e23039fc110afff0ac01fbfb
7
- data.tar.gz: 6c78ad6a554b6f80266c7e9cef4003dae98cb1005f5a71cfa19d7fc46c7d6c7b71f88835da81b1382a0b3a46abcf0153bade3ca5b93b1ae71971101c456d0286
6
+ metadata.gz: 14004eb8a7fac00b1b6aa96729c0a69dd685cc76b0631e57a190894dac5aea81bc67da20744738f423b88a6d968246d75a3e6dc01be1ab8b0d8b84d7beab996a
7
+ data.tar.gz: 8e2ba75e78b4785045f5d1e87d2d264577ce50ff41fc7f09ca03bed801db20e2af0890635192929d6767f86355846aa21b10edc127f11b72b5f91a253ace7a6b
data/.rubocop.yml CHANGED
@@ -1,14 +1,14 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
- require:
4
- - rubocop/cop/internal_affairs
3
+ plugins:
4
+ - rubocop-internal_affairs
5
5
  - rubocop-performance
6
6
  - rubocop-rake
7
7
  - rubocop-rspec
8
8
 
9
9
  AllCops:
10
10
  NewCops: enable
11
- TargetRubyVersion: 2.6
11
+ TargetRubyVersion: 2.7
12
12
  SuggestExtensions: false
13
13
 
14
14
  Layout/LineLength:
@@ -30,5 +30,9 @@ Style/StringLiterals:
30
30
  Style/StringLiteralsInInterpolation:
31
31
  EnforcedStyle: double_quotes
32
32
 
33
+ RSpec/DescribeClass:
34
+ Exclude:
35
+ - spec/project/**/*.rb
36
+
33
37
  RSpec/ExampleLength:
34
38
  Enabled: false
data/.simplecov ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ SimpleCov.start do
4
+ enable_coverage :branch
5
+ add_filter "/spec/"
6
+ add_filter "/vendor/bundle/"
7
+ end
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.0.0 (2025-04-02)
6
+
7
+ ### New features
8
+
9
+ - [#8](https://github.com/rubocop/rubocop-committee/pull/8): Pluginfy RuboCop Committee. ([@ydah][])
10
+
11
+ ### Changes
12
+
13
+ - [#4](https://github.com/rubocop/rubocop-committee/pull/4): Drop Ruby 2.6 runtime support. ([@ydah])
14
+
5
15
  ## 0.1.1 (2022-12-29)
6
16
 
7
17
  - Add rubocop-rspec in runtime dependency. ([@ydah])
@@ -10,6 +20,6 @@
10
20
 
11
21
  - Initial release ([@ydah])
12
22
 
13
- <!-- Contributors -->
23
+ <!-- Contributors (alphabetically) -->
14
24
 
15
25
  [@ydah]: https://github.com/ydah
data/CODE_OF_CONDUCT.md CHANGED
@@ -67,7 +67,7 @@ Community leaders will follow these Community Impact Guidelines in determining t
67
67
 
68
68
  ### 4. Permanent Ban
69
69
 
70
- **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
71
 
72
72
  **Consequence**: A permanent ban from any sort of public interaction within the community.
73
73
 
data/Gemfile CHANGED
@@ -6,7 +6,9 @@ gemspec
6
6
 
7
7
  gem "bump", require: false
8
8
  gem "rake"
9
- gem "rspec"
10
- gem "rubocop-performance"
11
- gem "rubocop-rake"
9
+ gem "rspec", "~> 3.11"
10
+ gem "rubocop-performance", "~> 1.7"
11
+ gem "rubocop-rake", "~> 0.7"
12
+ gem "rubocop-rspec", "~> 3.5"
13
+ gem "simplecov", ">= 0.19"
12
14
  gem "yard"
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![GitHub top language](https://img.shields.io/github/languages/top/ydah/rubocop-committee?color=39ff14) [![Gem Version](https://badge.fury.io/rb/rubocop-committee.svg)](https://badge.fury.io/rb/rubocop-committee) [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop) [![CI](https://github.com/ydah/rubocop-committee/actions/workflows/ci.yml/badge.svg)](https://github.com/ydah/rubocop-committee/actions/workflows/ci.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/a1b121696e9d1b425406/maintainability)](https://codeclimate.com/github/ydah/rubocop-committee/maintainability)
4
4
 
5
- Committee-specific analysis for your projects, as an extension to
5
+ [Committee](https://github.com/interagent/committee)-specific analysis for your projects, as an extension to
6
6
  [RuboCop](https://github.com/rubocop/rubocop).
7
7
 
8
8
  ## Installation
@@ -29,13 +29,13 @@ ways to do this:
29
29
  Put this into your `.rubocop.yml`.
30
30
 
31
31
  ```yaml
32
- require: rubocop-committee
32
+ plugins: rubocop-committee
33
33
  ```
34
34
 
35
35
  Alternatively, use the following array notation when specifying multiple extensions.
36
36
 
37
37
  ```yaml
38
- require:
38
+ plugins:
39
39
  - rubocop-other-extension
40
40
  - rubocop-committee
41
41
  ```
@@ -43,17 +43,20 @@ require:
43
43
  Now you can run `rubocop` and it will automatically load the RuboCop Committee
44
44
  cops together with the standard cops.
45
45
 
46
+ > [!NOTE]
47
+ > The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
48
+
46
49
  ### Command line
47
50
 
48
51
  ```bash
49
- rubocop --require rubocop-committee
52
+ rubocop --plugin rubocop-committee
50
53
  ```
51
54
 
52
55
  ### Rake task
53
56
 
54
57
  ```ruby
55
58
  RuboCop::RakeTask.new do |task|
56
- task.requires << 'rubocop-committee'
59
+ task.plugins << 'rubocop-committee'
57
60
  end
58
61
  ```
59
62
 
data/config/default.yml CHANGED
@@ -6,14 +6,14 @@ inherit_mode:
6
6
  Committee:
7
7
  Enabled: true
8
8
 
9
+ Committee/RedundantResponseStatusAssertions:
10
+ Description: Check for validation of redundant response HTTP status codes.
11
+ Enabled: pending
12
+ VersionAdded: "0.1"
13
+
9
14
  Committee/UnspecifiedExpectedStatus:
10
15
  Description: |
11
16
  Check if the status code is specified as an argument to the method of the Committee
12
17
  where the expected response status code is required.
13
18
  Enabled: pending
14
- VersionAdded: '0.1'
15
-
16
- Committee/RedundantResponseStatusAssertions:
17
- Description: Check for validation of redundant response HTTP status codes.
18
- Enabled: pending
19
- VersionAdded: '0.1'
19
+ VersionAdded: "0.1"
data/docs/antora.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: rubocop-committee
2
2
  title: RuboCop Committee
3
- version: "0.1.1"
3
+ version: '1.0'
4
4
  nav:
5
5
  - modules/ROOT/nav.adoc
@@ -1,66 +1,75 @@
1
+ ////
2
+ Do NOT edit this file by hand directly, as it is automatically generated.
3
+
4
+ Please make any necessary changes to the cop documentation within the source files themselves.
5
+ ////
6
+
1
7
  = Committee
2
8
 
9
+ [#committeeredundantresponsestatusassertions]
3
10
  == Committee/RedundantResponseStatusAssertions
4
11
 
5
12
  |===
6
13
  | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
7
14
 
8
- | Pending
15
+ | Enabled
9
16
  | Yes
10
- | Yes
11
- | 0.1
17
+ | Always
18
+ | -
12
19
  | -
13
20
  |===
14
21
 
15
22
  Check for validation of redundant response HTTP status codes.
16
23
 
24
+ [#examples-committeeredundantresponsestatusassertions]
17
25
  === Examples
18
26
 
19
27
  [source,ruby]
20
28
  ----
21
29
  # bad
22
- it 'something' do
30
+ it 'does something' do
23
31
  subject
24
32
  expect(response).to have_http_status 400
25
33
  assert_schema_conform(400)
26
34
  end
27
35
 
28
36
  # good
29
- it 'something' do
37
+ it 'does something' do
30
38
  subject
31
39
  assert_schema_conform(400)
32
40
  end
33
41
  ----
34
42
 
43
+ [#committeeunspecifiedexpectedstatus]
35
44
  == Committee/UnspecifiedExpectedStatus
36
45
 
37
46
  |===
38
47
  | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
39
48
 
40
- | Pending
49
+ | Enabled
41
50
  | Yes
42
- | Yes
43
- | 0.1
51
+ | Always
52
+ | -
44
53
  | -
45
54
  |===
46
55
 
47
56
  Check if the status code is specified as an argument to the method of the Committee
48
- where the expected response status code is required.
57
+ where the expected response HTTP status code is required.
49
58
 
59
+ [#examples-committeeunspecifiedexpectedstatus]
50
60
  === Examples
51
61
 
52
62
  [source,ruby]
53
63
  ----
54
64
  # bad
55
- it 'something' do
65
+ it 'does something' do
56
66
  subject
57
- expect(response).to have_http_status 400
58
67
  assert_schema_conform
59
68
  end
60
69
 
61
70
  # good
62
- it 'something' do
71
+ it 'does something' do
63
72
  subject
64
- assert_schema_conform(400)
73
+ assert_schema_conform(200)
65
74
  end
66
75
  ----
@@ -1,6 +1,6 @@
1
1
  = RuboCop Committee
2
2
 
3
- Committee-specific analysis for your projects, as an extension to
3
+ https://github.com/interagent/committee[Committee]-specific analysis for your projects, as an extension to
4
4
  https://github.com/rubocop/rubocop[RuboCop].
5
5
 
6
6
  RuboCop Committee follows the https://docs.rubocop.org/rubocop/versioning.html[RuboCop versioning guide].
@@ -8,13 +8,13 @@ There are some ways to do this:
8
8
  Put this into your `.rubocop.yml`:
9
9
 
10
10
  ----
11
- require: rubocop-committee
11
+ plugins: rubocop-committee
12
12
  ----
13
13
 
14
14
  or, if you are using several extensions:
15
15
 
16
16
  ----
17
- require:
17
+ plugins:
18
18
  - rubocop-committee
19
19
  - rubocop-rspec
20
20
  ----
@@ -24,7 +24,7 @@ cops together with the standard cops.
24
24
 
25
25
  [source,bash]
26
26
  ----
27
- $ rubocop --require rubocop-committee
27
+ $ rubocop --plugin rubocop-committee
28
28
  ----
29
29
 
30
30
  == Rake task
@@ -32,6 +32,8 @@ $ rubocop --require rubocop-committee
32
32
  [source,ruby]
33
33
  ----
34
34
  RuboCop::RakeTask.new do |task|
35
- task.requires << 'rubocop-committee'
35
+ task.plugins << 'rubocop-committee'
36
36
  end
37
37
  ----
38
+
39
+ NOTE: The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lint_roller"
4
+
5
+ module RuboCop
6
+ module Committee
7
+ # A plugin that integrates RuboCop Committee with RuboCop's plugin system.
8
+ class Plugin < LintRoller::Plugin
9
+ def about
10
+ LintRoller::About.new(
11
+ name: "rubocop-committee",
12
+ version: Version::STRING,
13
+ homepage: "https://github.com/ydah/rubocop-committee",
14
+ description: "Committee-specific analysis for your projects, as an extension to RuboCop."
15
+ )
16
+ end
17
+
18
+ def supported?(context)
19
+ context.engine == :rubocop
20
+ end
21
+
22
+ def rules(_context)
23
+ project_root = Pathname.new(__dir__).join("../../..")
24
+
25
+ LintRoller::Rules.new(type: :path, config_format: :rubocop, value: project_root.join("config", "default.yml"))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Rubocop
4
4
  module Committee
5
- VERSION = "0.1.1"
5
+ module Version
6
+ STRING = "1.0.0"
7
+ end
6
8
  end
7
9
  end
@@ -7,14 +7,14 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  # # bad
10
- # it 'something' do
10
+ # it 'does something' do
11
11
  # subject
12
12
  # expect(response).to have_http_status 400
13
13
  # assert_schema_conform(400)
14
14
  # end
15
15
  #
16
16
  # # good
17
- # it 'something' do
17
+ # it 'does something' do
18
18
  # subject
19
19
  # assert_schema_conform(400)
20
20
  # end
@@ -31,11 +31,11 @@ module RuboCop
31
31
  $(send nil? :have_http_status (:int _))
32
32
  PATTERN
33
33
 
34
- def on_send(node)
34
+ def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
35
35
  return if node.first_argument.nil?
36
36
 
37
37
  have_http_status(node.parent) do |http_node|
38
- return autocorrect(node, http_node.parent.loc.expression)
38
+ autocorrect(node, http_node.parent.source_range)
39
39
  end
40
40
  end
41
41
 
@@ -4,20 +4,19 @@ module RuboCop
4
4
  module Cop
5
5
  module Committee
6
6
  # Check if the status code is specified as an argument to the method of the Committee
7
- # where the expected response status code is required.
7
+ # where the expected response HTTP status code is required.
8
8
  #
9
9
  # @example
10
10
  # # bad
11
- # it 'something' do
11
+ # it 'does something' do
12
12
  # subject
13
- # expect(response).to have_http_status 400
14
13
  # assert_schema_conform
15
14
  # end
16
15
  #
17
16
  # # good
18
- # it 'something' do
17
+ # it 'does something' do
19
18
  # subject
20
- # assert_schema_conform(400)
19
+ # assert_schema_conform(200)
21
20
  # end
22
21
  #
23
22
  class UnspecifiedExpectedStatus < Base
@@ -32,7 +31,7 @@ module RuboCop
32
31
  (send nil? :have_http_status (:int $_))
33
32
  PATTERN
34
33
 
35
- def on_send(node)
34
+ def on_send(node) # rubocop:disable InternalAffairs/OnSendWithoutOnCSend
36
35
  return if node.arguments?
37
36
 
38
37
  have_http_status(node.parent) do |status|
@@ -1,18 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "rubocop/committee/inject"
3
+ require "rubocop"
4
+
4
5
  require_relative "rubocop/committee/version"
6
+ require_relative "rubocop/committee/plugin"
5
7
 
6
8
  require_relative "rubocop/cop/committee/redundant_response_status_assertions"
7
9
  require_relative "rubocop/cop/committee/unspecified_expected_status"
8
-
9
- module RuboCop
10
- module Committee
11
- PROJECT_ROOT = ::Pathname.new(__dir__).parent.expand_path.freeze
12
- CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
13
- CONFIG = ::YAML.safe_load(CONFIG_DEFAULT.read).freeze
14
- private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
15
- end
16
- end
17
-
18
- RuboCop::Committee::Inject.defaults!
@@ -0,0 +1,10 @@
1
+ ### New features
2
+
3
+ - [#8](https://github.com/rubocop/rubocop-committee/pull/8): Pluginfy RuboCop Committee. ([@ydah][])
4
+
5
+ ### Changes
6
+
7
+ - [#4](https://github.com/rubocop/rubocop-committee/pull/4): Drop Ruby 2.6 runtime support. ([@ydah])
8
+
9
+ [@ydah][]: https://github.com/ydah][
10
+ [@ydah]: https://github.com/ydah
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/rubocop/committee/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rubocop-committee"
7
+ spec.version = Rubocop::Committee::Version::STRING
8
+ spec.authors = ["ydah"]
9
+ spec.email = ["t.yudai92@gmail.com"]
10
+
11
+ spec.summary = "Automatic committee code style checking tool."
12
+ spec.description = <<~DESCRIPTION
13
+ Automatic committee code style checking tool.
14
+ A RuboCop extension focused on enforcing committee.
15
+ DESCRIPTION
16
+ spec.homepage = "https://github.com/ydah/rubocop-committee"
17
+ spec.license = "MIT"
18
+ spec.required_ruby_version = ">= 2.7.0"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
23
+ spec.metadata["rubygems_mfa_required"] = "true"
24
+ spec.metadata["default_lint_roller_plugin"] = "RuboCop::Committee::Plugin"
25
+
26
+ # Specify which files should be added to the gem when it is released.
27
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
28
+ spec.files = Dir.chdir(__dir__) do
29
+ `git ls-files -z`.split("\x0").reject do |f|
30
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
31
+ end
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_dependency "lint_roller", "~> 1.1"
38
+ spec.add_dependency "rubocop", ">= 1.72.1", "< 2.0"
39
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ autoload :Changelog, "#{__dir__}/changelog"
4
+
5
+ namespace :changelog do
6
+ %i[new fix change].each do |type|
7
+ desc "Create a Changelog entry (#{type})"
8
+ task type, [:id] do |_task, args|
9
+ ref_type = :pull if args[:id]
10
+ path = Changelog::Entry.new(type: type, ref_id: args[:id], ref_type: ref_type).write
11
+ cmd = "git add #{path}"
12
+ system cmd
13
+ puts "Entry '#{path}' created and added to git index"
14
+ end
15
+ end
16
+
17
+ desc "Merge entries and delete them"
18
+ task :merge do
19
+ raise "No entries!" unless Changelog.pending?
20
+
21
+ Changelog.new.merge!.and_delete!
22
+ cmd = "git commit -a -m 'Update Changelog'"
23
+ puts cmd
24
+ system cmd
25
+ end
26
+
27
+ desc "Check to see if there are any entries left"
28
+ task :check_clean do
29
+ next unless Changelog.pending?
30
+
31
+ puts "*** Pending changelog entries!"
32
+ puts "Do `bundle exec rake changelog:merge`"
33
+ exit(1)
34
+ end
35
+ end
@@ -0,0 +1,193 @@
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
+ CONTRIBUTORS_HEADER = /#{Regexp.escape("<!-- Contributors (alphabetically) -->\n\n")}/m.freeze
13
+ ENTRIES_PATH_TEMPLATE = "#{ENTRIES_PATH}%<type>s_%<name>s.md"
14
+ TYPE_REGEXP = /#{Regexp.escape(ENTRIES_PATH)}([a-z]+)_/.freeze
15
+ TYPE_TO_HEADER = { new: "New features", fix: "Bug fixes", change: "Changes" }.freeze
16
+ HEADER = /### (.*)/.freeze
17
+ PATH = "CHANGELOG.md"
18
+ REF_URL = "https://github.com/rubocop/rubocop-committee"
19
+ MAX_LENGTH = 40
20
+ CONTRIBUTOR = "[@%<link>s]: https://github.com/%<user>s"
21
+ SIGNATURE = Regexp.new(format(Regexp.escape("[@%<user>s]"), user: '([\w-]+)'))
22
+ EOF = "\n"
23
+
24
+ # New entry
25
+ Entry = Struct.new(:type, :body, :ref_type, :ref_id, :user, keyword_init: true) do
26
+ def initialize(type:, body: last_commit_title, ref_type: nil, ref_id: nil, user: github_user)
27
+ id, body = extract_id(body)
28
+ ref_id ||= id || "x"
29
+ ref_type ||= id ? :issues : :pull
30
+ super
31
+ end
32
+
33
+ def write
34
+ FileUtils.mkdir_p(ENTRIES_PATH)
35
+ File.write(path, content)
36
+ path
37
+ end
38
+
39
+ def path
40
+ format(ENTRIES_PATH_TEMPLATE, type: type, name: str_to_filename(body))
41
+ end
42
+
43
+ def content
44
+ period = "." unless body.end_with? "."
45
+ "- #{ref}: #{body}#{period} ([@#{user}])\n"
46
+ end
47
+
48
+ def ref
49
+ "[##{ref_id}](#{REF_URL}/#{ref_type}/#{ref_id})"
50
+ end
51
+
52
+ def last_commit_title
53
+ `git log -1 --pretty=%B`.lines.first.chomp
54
+ end
55
+
56
+ def extract_id(body)
57
+ /^\[Fix(?:es)? #(\d+)\] (.*)/.match(body)&.captures || [nil, body]
58
+ end
59
+
60
+ def str_to_filename(str)
61
+ str
62
+ .split
63
+ .reject(&:empty?)
64
+ .map { |s| prettify(s) }
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
+
80
+ private
81
+
82
+ def prettify(str)
83
+ str.gsub!(/\W/, "_")
84
+
85
+ # Separate word boundaries by `_`.
86
+ str.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
87
+ (Regexp.last_match(1) || Regexp.last_match(2)) << "_"
88
+ end
89
+
90
+ str.gsub!(/\A_+|_+\z/, "")
91
+ str.downcase!
92
+ str
93
+ end
94
+ end
95
+
96
+ def self.pending?
97
+ entry_paths.any?
98
+ end
99
+
100
+ def self.entry_paths
101
+ Dir["#{ENTRIES_PATH}*"]
102
+ end
103
+
104
+ def self.read_entries
105
+ entry_paths.to_h { |path| [path, File.read(path)] }
106
+ end
107
+
108
+ attr_reader :header, :rest
109
+
110
+ def initialize(content: File.read(PATH), entries: Changelog.read_entries)
111
+ require "strscan"
112
+
113
+ parse(content)
114
+ @entries = entries
115
+ end
116
+
117
+ def and_delete!
118
+ @entries.each_key { |path| File.delete(path) }
119
+ end
120
+
121
+ def merge!
122
+ File.write(PATH, merge_content)
123
+ self
124
+ end
125
+
126
+ def unreleased_content
127
+ entry_map = parse_entries(@entries)
128
+ merged_map = merge_entries(entry_map)
129
+ merged_map.flat_map do |header, things|
130
+ ["### #{header}\n", *things, ""]
131
+ end.join("\n")
132
+ end
133
+
134
+ def merge_content
135
+ merged_content = [@header, unreleased_content, @changes.chomp, *all_contributors].join("\n")
136
+
137
+ merged_content << EOF
138
+ end
139
+
140
+ def all_contributors
141
+ (@contributors.split(/\R/) + new_contributors).uniq.sort
142
+ end
143
+
144
+ def new_contributors
145
+ contributors
146
+ .map { |user| format(CONTRIBUTOR, link: user.downcase, user: user) }
147
+ end
148
+
149
+ def contributors
150
+ contributors = @entries.values.flat_map do |entry|
151
+ entry.match(/\. \((?<contributors>.+)\)\n/)[:contributors].split(",")
152
+ end
153
+
154
+ contributors.join.scan(SIGNATURE).flatten
155
+ end
156
+
157
+ private
158
+
159
+ def merge_entries(entry_map)
160
+ all = @unreleased.merge(entry_map) { |_k, v1, v2| v1.concat(v2) }
161
+ canonical = TYPE_TO_HEADER.values.to_h { |v| [v, nil] }
162
+ canonical.merge(all).compact
163
+ end
164
+
165
+ def parse(content)
166
+ ss = StringScanner.new(content)
167
+ @header = ss.scan_until(FIRST_HEADER)
168
+ @unreleased = parse_release(ss.scan_until(/\n(?=## )/m))
169
+ @changes = ss.scan_until(CONTRIBUTORS_HEADER)
170
+ @contributors = ss.rest
171
+ end
172
+
173
+ # @return [Hash<type, Array<String>]]
174
+ def parse_release(unreleased)
175
+ unreleased
176
+ .lines
177
+ .map(&:chomp)
178
+ .reject(&:empty?)
179
+ .slice_before(HEADER)
180
+ .to_h do |header, *entries|
181
+ [HEADER.match(header)[1], entries]
182
+ end
183
+ end
184
+
185
+ def parse_entries(path_content_map)
186
+ changes = Hash.new { |h, k| h[k] = [] }
187
+ path_content_map.each do |path, content|
188
+ header = TYPE_TO_HEADER.fetch(TYPE_REGEXP.match(path)[1].to_sym)
189
+ changes[header].concat(content.lines.map(&:chomp))
190
+ end
191
+ changes
192
+ end
193
+ end
@@ -3,18 +3,40 @@
3
3
  require "bump"
4
4
 
5
5
  namespace :cut_release do
6
- def update_file(path)
7
- content = File.read(path)
8
- File.write(path, yield(content))
9
- end
10
-
11
6
  %w[major minor patch pre].each do |release_type|
12
- desc "Cut a new #{release_type} release and update documents."
13
- task release_type do
7
+ desc "Cut a new #{release_type} release and create release notes."
8
+ task release_type => "changelog:check_clean" do
14
9
  run(release_type)
15
10
  end
16
11
  end
17
12
 
13
+ def add_header_to_changelog(version)
14
+ update_file("CHANGELOG.md") do |changelog|
15
+ changelog.sub("## Master (Unreleased)\n\n",
16
+ "\\0## #{version} (#{Time.now.strftime("%F")})\n\n")
17
+ end
18
+ end
19
+
20
+ def create_release_notes(version)
21
+ release_notes = new_version_changes.strip
22
+ contributor_links = user_links(release_notes)
23
+
24
+ File.open("relnotes/v#{version}.md", "w") do |file|
25
+ file << release_notes
26
+ file << "\n\n"
27
+ file << contributor_links
28
+ file << "\n"
29
+ end
30
+ end
31
+
32
+ def update_antora_yml(new_version)
33
+ antora_metadata = File.read("docs/antora.yml")
34
+
35
+ File.open("docs/antora.yml", "w") do |f|
36
+ f << antora_metadata.sub("version: ~", "version: '#{version_sans_patch(new_version)}'")
37
+ end
38
+ end
39
+
18
40
  def version_sans_patch(version)
19
41
  version.split(".").take(2).join(".")
20
42
  end
@@ -28,6 +50,22 @@ namespace :cut_release do
28
50
  RuboCop::ConfigLoader.default_configuration = nil # invalidate loaded conf
29
51
  end
30
52
 
53
+ def new_version_changes
54
+ changelog = File.read("CHANGELOG.md")
55
+ _, _, new_changes, _older_changes = changelog.split(/^## .*$/, 4)
56
+ new_changes
57
+ end
58
+
59
+ def update_file(path)
60
+ content = File.read(path)
61
+ File.write(path, yield(content))
62
+ end
63
+
64
+ def user_links(text)
65
+ names = text.scan(/\[@(\S+)\]/).map(&:first).uniq
66
+ names.map { |name| "[@#{name}]: https://github.com/#{name}" }.join("\n")
67
+ end
68
+
31
69
  def update_docs(version)
32
70
  update_file("docs/antora.yml") do |antora_metadata|
33
71
  antora_metadata.sub("version: ~",
@@ -35,13 +73,6 @@ namespace :cut_release do
35
73
  end
36
74
  end
37
75
 
38
- def add_header_to_changelog(version)
39
- update_file("CHANGELOG.md") do |changelog|
40
- changelog.sub("## Master (Unreleased)\n\n",
41
- '\0' "## #{version} (#{Time.now.strftime("%F")})\n\n")
42
- end
43
- end
44
-
45
76
  def run(release_type)
46
77
  old_version = Bump::Bump.current
47
78
  Bump::Bump.run(release_type, commit: false, bundle: false, tag: false)
@@ -50,7 +81,10 @@ namespace :cut_release do
50
81
  update_cop_versions(new_version)
51
82
  `bundle exec rake generate_cops_documentation`
52
83
  update_docs(new_version) if %w[major minor].include?(release_type)
84
+
53
85
  add_header_to_changelog(new_version)
86
+ create_release_notes(new_version)
87
+ update_antora_yml(new_version)
54
88
 
55
89
  puts "Changed version from #{old_version} to #{new_version}."
56
90
  end
metadata CHANGED
@@ -1,43 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-committee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ydah
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2022-12-29 00:00:00.000000000 Z
10
+ date: 2025-04-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: rubocop
13
+ name: lint_roller
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - ">="
16
+ - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '0'
18
+ version: '1.1'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
- - - ">="
23
+ - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '0'
25
+ version: '1.1'
27
26
  - !ruby/object:Gem::Dependency
28
- name: rubocop-rspec
27
+ name: rubocop
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: '0'
32
+ version: 1.72.1
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '2.0'
34
36
  type: :runtime
35
37
  prerelease: false
36
38
  version_requirements: !ruby/object:Gem::Requirement
37
39
  requirements:
38
40
  - - ">="
39
41
  - !ruby/object:Gem::Version
40
- version: '0'
42
+ version: 1.72.1
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '2.0'
41
46
  description: |
42
47
  Automatic committee code style checking tool.
43
48
  A RuboCop extension focused on enforcing committee.
@@ -51,6 +56,7 @@ files:
51
56
  - ".rspec"
52
57
  - ".rubocop.yml"
53
58
  - ".rubocop_todo.yml"
59
+ - ".simplecov"
54
60
  - ".yamllint.yml"
55
61
  - ".yardopts"
56
62
  - CHANGELOG.md
@@ -68,10 +74,14 @@ files:
68
74
  - docs/modules/ROOT/pages/installation.adoc
69
75
  - docs/modules/ROOT/pages/usage.adoc
70
76
  - lib/rubocop-committee.rb
71
- - lib/rubocop/committee/inject.rb
77
+ - lib/rubocop/committee/plugin.rb
72
78
  - lib/rubocop/committee/version.rb
73
79
  - lib/rubocop/cop/committee/redundant_response_status_assertions.rb
74
80
  - lib/rubocop/cop/committee/unspecified_expected_status.rb
81
+ - relnotes/v1.0.0.md
82
+ - rubocop-committee.gemspec
83
+ - tasks/changelog.rake
84
+ - tasks/changelog.rb
75
85
  - tasks/cops_documentation.rake
76
86
  - tasks/cut_release.rake
77
87
  - tasks/new_cop.rake
@@ -83,7 +93,7 @@ metadata:
83
93
  source_code_uri: https://github.com/ydah/rubocop-committee
84
94
  changelog_uri: https://github.com/ydah/rubocop-committee/releases
85
95
  rubygems_mfa_required: 'true'
86
- post_install_message:
96
+ default_lint_roller_plugin: RuboCop::Committee::Plugin
87
97
  rdoc_options: []
88
98
  require_paths:
89
99
  - lib
@@ -91,15 +101,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
101
  requirements:
92
102
  - - ">="
93
103
  - !ruby/object:Gem::Version
94
- version: 2.6.0
104
+ version: 2.7.0
95
105
  required_rubygems_version: !ruby/object:Gem::Requirement
96
106
  requirements:
97
107
  - - ">="
98
108
  - !ruby/object:Gem::Version
99
109
  version: '0'
100
110
  requirements: []
101
- rubygems_version: 3.3.3
102
- signing_key:
111
+ rubygems_version: 3.6.2
103
112
  specification_version: 4
104
113
  summary: Automatic committee code style checking tool.
105
114
  test_files: []
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rubocop"
4
- require "rubocop-rspec"
5
-
6
- module RuboCop
7
- module Committee
8
- module Inject
9
- def self.defaults!
10
- path = CONFIG_DEFAULT.to_s
11
- hash = ::RuboCop::ConfigLoader.send(:load_yaml_configuration, path)
12
- config = ::RuboCop::Config.new(hash, path).tap(&:make_excludes_absolute)
13
- puts "configuration from #{path}" if ::RuboCop::ConfigLoader.debug?
14
- config = ::RuboCop::ConfigLoader.merge_with_default(config, path)
15
- ::RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, config)
16
- end
17
- end
18
- end
19
- end