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 +4 -4
- data/.rubocop.yml +7 -3
- data/.simplecov +7 -0
- data/CHANGELOG.md +11 -1
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +5 -3
- data/README.md +8 -5
- data/config/default.yml +6 -6
- data/docs/antora.yml +1 -1
- data/docs/modules/ROOT/pages/cops_committee.adoc +22 -13
- data/docs/modules/ROOT/pages/index.adoc +1 -1
- data/docs/modules/ROOT/pages/usage.adoc +6 -4
- data/lib/rubocop/committee/plugin.rb +29 -0
- data/lib/rubocop/committee/version.rb +3 -1
- data/lib/rubocop/cop/committee/redundant_response_status_assertions.rb +4 -4
- data/lib/rubocop/cop/committee/unspecified_expected_status.rb +5 -6
- data/lib/rubocop-committee.rb +3 -12
- data/relnotes/v1.0.0.md +10 -0
- data/rubocop-committee.gemspec +39 -0
- data/tasks/changelog.rake +35 -0
- data/tasks/changelog.rb +193 -0
- data/tasks/cut_release.rake +48 -14
- metadata +25 -16
- data/lib/rubocop/committee/inject.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff90da55bb78b45d0022371df0b3a2f0cd6d54c7c0714f79cb95f7878e34d285
|
4
|
+
data.tar.gz: d19b4f2aa1c16ae1de412f1ed7ba076a578f936a624334e7c80ed9a728ee5e59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
4
|
-
- rubocop
|
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.
|
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
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,
|
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
|
 [](https://badge.fury.io/rb/rubocop-committee) [](https://github.com/rubocop/rubocop) [](https://github.com/ydah/rubocop-committee/actions/workflows/ci.yml) [](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
|
-
|
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
|
-
|
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 --
|
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.
|
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:
|
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,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
|
-
|
|
15
|
+
| Enabled
|
9
16
|
| Yes
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
49
|
+
| Enabled
|
41
50
|
| Yes
|
42
|
-
|
|
43
|
-
|
|
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(
|
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
|
-
|
11
|
+
plugins: rubocop-committee
|
12
12
|
----
|
13
13
|
|
14
14
|
or, if you are using several extensions:
|
15
15
|
|
16
16
|
----
|
17
|
-
|
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 --
|
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.
|
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
|
@@ -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
|
-
|
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(
|
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|
|
data/lib/rubocop-committee.rb
CHANGED
@@ -1,18 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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!
|
data/relnotes/v1.0.0.md
ADDED
@@ -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
|
data/tasks/changelog.rb
ADDED
@@ -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
|
data/tasks/cut_release.rake
CHANGED
@@ -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
|
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.
|
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:
|
10
|
+
date: 2025-04-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
13
|
+
name: lint_roller
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
|
-
- - "
|
16
|
+
- - "~>"
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
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: '
|
25
|
+
version: '1.1'
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: rubocop
|
27
|
+
name: rubocop
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
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:
|
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/
|
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
|
-
|
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.
|
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.
|
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
|