rubocop-committee 0.1.0 → 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: 85d35285a988e66ac1d5976d7ac3bf7ac7f207015d1fcd352eed7b8bdac60625
4
- data.tar.gz: 6c2d9fa4b9d4d28bcbb596446e750a4befd6f0674301d1f03a1f5a604a5679b7
3
+ metadata.gz: ff90da55bb78b45d0022371df0b3a2f0cd6d54c7c0714f79cb95f7878e34d285
4
+ data.tar.gz: d19b4f2aa1c16ae1de412f1ed7ba076a578f936a624334e7c80ed9a728ee5e59
5
5
  SHA512:
6
- metadata.gz: 2af73171d6c98048f001c48be91ebcf2a7c92c1dce94c1af6fb07cb91e1ace600f52d6787c3792dd12929a93e934fa1ac22f3e2db8c91831d21f1e9f65706436
7
- data.tar.gz: 2fcb0125bdece926274d5b9cfab219497126bf3dbc599c386daa8ed3e02069c3a73f710c2de2d0efc98c2d24c213005b822de4c36c54a5181c9ec402a0fe96dc
6
+ metadata.gz: 14004eb8a7fac00b1b6aa96729c0a69dd685cc76b0631e57a190894dac5aea81bc67da20744738f423b88a6d968246d75a3e6dc01be1ab8b0d8b84d7beab996a
7
+ data.tar.gz: 8e2ba75e78b4785045f5d1e87d2d264577ce50ff41fc7f09ca03bed801db20e2af0890635192929d6767f86355846aa21b10edc127f11b72b5f91a253ace7a6b
data/.rubocop.yml CHANGED
@@ -1,12 +1,14 @@
1
- require:
2
- - rubocop/cop/internal_affairs
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ plugins:
4
+ - rubocop-internal_affairs
3
5
  - rubocop-performance
4
6
  - rubocop-rake
5
7
  - rubocop-rspec
6
8
 
7
9
  AllCops:
8
10
  NewCops: enable
9
- TargetRubyVersion: 2.6
11
+ TargetRubyVersion: 2.7
10
12
  SuggestExtensions: false
11
13
 
12
14
  Layout/LineLength:
@@ -28,5 +30,9 @@ Style/StringLiterals:
28
30
  Style/StringLiteralsInInterpolation:
29
31
  EnforcedStyle: double_quotes
30
32
 
33
+ RSpec/DescribeClass:
34
+ Exclude:
35
+ - spec/project/**/*.rb
36
+
31
37
  RSpec/ExampleLength:
32
38
  Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,12 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config --auto-gen-only-exclude --no-exclude-limit --no-auto-gen-timestamp`
3
+ # using RuboCop version 1.41.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 6
10
+ Rake/MethodDefinitionInTask:
11
+ Exclude:
12
+ - 'tasks/cut_release.rake'
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
@@ -1,9 +1,25 @@
1
- ## Unreleased
1
+ # Changelog
2
2
 
3
- ## 0.1.0 - 2022-12-29
3
+ ## Master (Unreleased)
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
+
15
+ ## 0.1.1 (2022-12-29)
16
+
17
+ - Add rubocop-rspec in runtime dependency. ([@ydah])
18
+
19
+ ## 0.1.0 (2022-12-29)
4
20
 
5
21
  - Initial release ([@ydah])
6
22
 
7
- <!-- Contributors -->
23
+ <!-- Contributors (alphabetically) -->
8
24
 
9
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
@@ -4,10 +4,11 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'bump', require: false
7
+ gem "bump", require: false
8
8
  gem "rake"
9
- gem "rspec"
10
- gem "rubocop-performance"
11
- gem "rubocop-rake"
12
- gem "rubocop-rspec"
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"
13
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,23 +43,26 @@ 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
 
60
63
  ## Documentation
61
64
 
62
- You can read more about RuboCop Committee in its official manual.
65
+ You can read more about RuboCop Committee in its [official manual](https://ydah.github.io/rubocop.docs/rubocop-committee/).
63
66
 
64
67
  ## The Cops
65
68
 
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"
@@ -1,5 +1,5 @@
1
1
  name: rubocop-committee
2
2
  title: RuboCop Committee
3
- version: "0.1.0"
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.0"
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,29 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-committee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
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-28 00:00:00.000000000 Z
10
+ date: 2025-04-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: lint_roller
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.1'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: rubocop
15
28
  requirement: !ruby/object:Gem::Requirement
16
29
  requirements:
17
30
  - - ">="
18
31
  - !ruby/object:Gem::Version
19
- version: '0'
32
+ version: 1.72.1
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '2.0'
20
36
  type: :runtime
21
37
  prerelease: false
22
38
  version_requirements: !ruby/object:Gem::Requirement
23
39
  requirements:
24
40
  - - ">="
25
41
  - !ruby/object:Gem::Version
26
- version: '0'
42
+ version: 1.72.1
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '2.0'
27
46
  description: |
28
47
  Automatic committee code style checking tool.
29
48
  A RuboCop extension focused on enforcing committee.
@@ -36,6 +55,8 @@ files:
36
55
  - ".codespellignore"
37
56
  - ".rspec"
38
57
  - ".rubocop.yml"
58
+ - ".rubocop_todo.yml"
59
+ - ".simplecov"
39
60
  - ".yamllint.yml"
40
61
  - ".yardopts"
41
62
  - CHANGELOG.md
@@ -45,18 +66,22 @@ files:
45
66
  - README.md
46
67
  - Rakefile
47
68
  - config/default.yml
69
+ - docs/antora.yml
48
70
  - docs/modules/ROOT/nav.adoc
49
71
  - docs/modules/ROOT/pages/cops.adoc
50
72
  - docs/modules/ROOT/pages/cops_committee.adoc
51
73
  - docs/modules/ROOT/pages/index.adoc
52
74
  - docs/modules/ROOT/pages/installation.adoc
53
75
  - docs/modules/ROOT/pages/usage.adoc
54
- - docs/modules/antora.yml
55
76
  - lib/rubocop-committee.rb
56
- - lib/rubocop/committee/inject.rb
77
+ - lib/rubocop/committee/plugin.rb
57
78
  - lib/rubocop/committee/version.rb
58
79
  - lib/rubocop/cop/committee/redundant_response_status_assertions.rb
59
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
60
85
  - tasks/cops_documentation.rake
61
86
  - tasks/cut_release.rake
62
87
  - tasks/new_cop.rake
@@ -68,7 +93,7 @@ metadata:
68
93
  source_code_uri: https://github.com/ydah/rubocop-committee
69
94
  changelog_uri: https://github.com/ydah/rubocop-committee/releases
70
95
  rubygems_mfa_required: 'true'
71
- post_install_message:
96
+ default_lint_roller_plugin: RuboCop::Committee::Plugin
72
97
  rdoc_options: []
73
98
  require_paths:
74
99
  - lib
@@ -76,15 +101,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
101
  requirements:
77
102
  - - ">="
78
103
  - !ruby/object:Gem::Version
79
- version: 2.6.0
104
+ version: 2.7.0
80
105
  required_rubygems_version: !ruby/object:Gem::Requirement
81
106
  requirements:
82
107
  - - ">="
83
108
  - !ruby/object:Gem::Version
84
109
  version: '0'
85
110
  requirements: []
86
- rubygems_version: 3.3.3
87
- signing_key:
111
+ rubygems_version: 3.6.2
88
112
  specification_version: 4
89
113
  summary: Automatic committee code style checking tool.
90
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