Skip to content

Commit d60a1e4

Browse files
czeisecamilopayanclaude
committed
Add CLAUDE.md and rubocop-update skill
Co-Authored-By: Camilo Payan <camilo.payan@testdouble.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 697036e commit d60a1e4

2 files changed

Lines changed: 194 additions & 0 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
name: rubocop-update
3+
description: Bump RuboCop (and standard-performance if a new version exists) to their latest released versions and open a pull request for the standard gem. Use this skill whenever someone asks to update, bump, or upgrade RuboCop, or when preparing a monthly standard release that tracks a new RuboCop version. Also use it when someone asks what new cops RuboCop shipped and how standard should handle them.
4+
---
5+
6+
# Monthly RuboCop Update
7+
8+
This skill automates the monthly RuboCop version bump for the `standard` gem. It updates the RuboCop and standard-performance dependencies, discovers new and changed cops, updates the changelog, bumps the standard version, and opens a pull request β€” leaving yml configuration of new cops as intentional follow-up work.
9+
10+
## Step 1: Determine current and latest versions
11+
12+
Read `standard.gemspec` to extract the current version constraints. The relevant lines look like:
13+
```ruby
14+
spec.add_dependency "rubocop", "~> 1.84.0"
15+
spec.add_dependency "standard-performance", "~> 1.8"
16+
```
17+
18+
Fetch the latest released versions in parallel from the RubyGems API:
19+
```
20+
GET https://rubygems.org/api/v1/gems/rubocop.json
21+
GET https://rubygems.org/api/v1/gems/standard-performance.json
22+
```
23+
Parse the `version` field from each response.
24+
25+
For rubocop: the current pinned minor is `X.Y` from `~> X.Y.0`. If the latest has the same `X.Y`, this is a patch-only update; otherwise it's a minor bump.
26+
27+
For standard-performance: the current pinned minor is `X.Y` from `~> X.Y`. Compare to the latest.
28+
29+
If neither gem has a newer version, stop and tell the user everything is already up to date.
30+
31+
## Step 2: Update the gemspec
32+
33+
In `standard.gemspec`:
34+
35+
- If rubocop has a new version, change its constraint to `"~> NEW_MAJOR.NEW_MINOR.0"`.
36+
Example: `"~> 1.84.0"` β†’ `"~> 1.85.0"`
37+
- If standard-performance has a new minor version, change its constraint to `"~> NEW_MAJOR.NEW_MINOR"`.
38+
Example: `"~> 1.8"` β†’ `"~> 1.9"`
39+
If standard-performance only has a patch update within the same minor, no gemspec change is needed β€” the existing pessimistic constraint already allows it.
40+
41+
## Step 3: Update the lockfile
42+
43+
```bash
44+
bundle update rubocop standard-performance
45+
```
46+
47+
(If only one gem changed, pass only that gem's name to `bundle update`.)
48+
49+
## Step 4: Bump the standard version
50+
51+
In `lib/standard/version.rb`, bump the version following this convention:
52+
- Minor bump in rubocop (or standard-performance) β†’ bump standard's minor version
53+
- Patch-only bump in both β†’ bump standard's patch version
54+
55+
Example: `1.54.0` β†’ `1.55.0` for a rubocop minor update.
56+
57+
Then run `bundle` so Bundler writes the new gem version to `Gemfile.lock`.
58+
59+
## Step 5: Find new and modified cops from the RuboCop changelog
60+
61+
Fetch the RuboCop CHANGELOG:
62+
```
63+
GET https://raw.githubusercontent.com/rubocop/rubocop/main/CHANGELOG.md
64+
```
65+
66+
Find all sections with headers between `## <new_rubocop_version>` and `## <old_rubocop_version>` (there may be multiple intermediate releases if we skipped a version). Within those sections, look for two categories:
67+
68+
**New cops** β€” lines in `### New features` that introduce a brand-new cop:
69+
- Pattern: contains "Add new `Cop/Name`" or "new cop `Cop/Name`"
70+
- Extract: cop name, PR URL, and one-sentence description from the changelog line
71+
72+
**Changed cops** β€” lines in `### Changes` (not bug fixes) that modify behavior of an existing cop:
73+
- Extract: cop name, PR URL, and what changed
74+
75+
Ignore `### Bug fixes` entries β€” those don't require configuration decisions.
76+
77+
If standard-performance also bumped, note it in the PR description but no cop-level changelog parsing is needed for it.
78+
79+
## Step 6: Update CHANGELOG.md
80+
81+
Prepend a new entry at the very top of `CHANGELOG.md`, following the existing format exactly:
82+
83+
```markdown
84+
## X.Y.Z
85+
86+
* Updates rubocop to [A.B.C](https://github.com/rubocop/rubocop/releases/tag/vA.B.C)
87+
* Updates standard-performance to [D.E.F](https://github.com/standardrb/standard-performance/releases/tag/vD.E.F)
88+
89+
```
90+
91+
Omit the standard-performance line if it didn't change. Keep every existing line unchanged.
92+
93+
## Step 7: Create a branch, commit, and open a PR
94+
95+
Create a branch named `update-rubocop-A.B.C`.
96+
97+
Stage and commit these files together:
98+
- `standard.gemspec`
99+
- `Gemfile.lock`
100+
- `lib/standard/version.rb`
101+
- `CHANGELOG.md`
102+
103+
Commit message: `Update rubocop to A.B.C` (include `, standard-performance to D.E.F` if it also changed).
104+
105+
Push the branch and open a PR. Title: **"Update rubocop to A.B.C"** (append `and standard-performance to D.E.F` if applicable).
106+
107+
PR description:
108+
109+
```
110+
Updates RuboCop from <old> to <new>.
111+
[If standard-performance changed: Updates standard-performance from <old> to <new>.]
112+
113+
## New cops
114+
115+
These cops were added and need a configuration decision before tests will pass:
116+
117+
| Cop | Description | PR |
118+
|-----|-------------|-----|
119+
| `Style/ExampleCop` | One-line description from changelog | [#12345](link) |
120+
121+
## Changed cops
122+
123+
These existing cops had behavioral changes:
124+
125+
| Cop | Change | PR |
126+
|-----|--------|-----|
127+
| `Style/ExistingCop` | What changed | [#12346](link) |
128+
129+
---
130+
131+
The `config/` YAML files have not been updated for any of the above cops.
132+
Tests are expected to fail until those configurations are added in a follow-up.
133+
```
134+
135+
Omit either table if empty. If there were no new or changed cops, note that in the description instead.

β€ŽCLAUDE.mdβ€Ž

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Commands
6+
7+
```sh
8+
# Run all tests and auto-fix standard violations
9+
./bin/rake
10+
11+
# Run only tests
12+
./bin/rake test
13+
14+
# Run a single test file
15+
ruby -Ilib -Itest test/standard/cli_test.rb
16+
17+
# Run standard linter (fix mode)
18+
./bin/rake standard:fix
19+
20+
# Release the gem
21+
./bin/rake release
22+
```
23+
24+
## Architecture
25+
26+
Standard Ruby is a linter/formatter built on top of RuboCop that provides an unconfigurable ruleset. The gem is intentionally opinionated β€” users cannot change the rules, only ignore violations.
27+
28+
### Request flow
29+
30+
`exe/standardrb` β†’ `Standard::Cli` β†’ `BuildsConfig` β†’ `LoadsRunner` β†’ runner
31+
32+
- **`BuildsConfig`** is the central orchestrator: it resolves `.standard.yml` and `.standard_todo.yml`, loads and merges settings from YAML + CLI args, then builds a `Standard::Config` struct (`runner`, `paths`, `rubocop_options`, `rubocop_config_store`).
33+
- **`CreatesConfigStore`** builds the `RuboCop::ConfigStore` by composing several single-responsibility objects: `AssignsRubocopYaml`, `SetsTargetRubyVersion`, `ConfiguresIgnoredPaths`, `MergesUserConfigExtensions`, and `Plugin::CombinesPluginConfigs`.
34+
- **`LoadsRunner`** resolves the correct runner class from `lib/standard/runners/` (`:rubocop`, `:lsp`, `:genignore`, `:help`, `:version`, `:verbose_version`).
35+
36+
### Plugin system
37+
38+
Since v1.28.0, Standard's own rules are loaded as plugins via [lint_roller](https://github.com/standardrb/lint_roller). The `standard` gem bundles `Standard::Base::Plugin` (`lib/standard/base/plugin.rb`), which selects a versioned YAML config from `config/` based on the project's target Ruby version (e.g. `config/ruby-3.3.yml` inherits from `config/base.yml`). Default plugins also include `standard-performance` and `standard-custom` (separate gems).
39+
40+
User-defined plugins are declared in `.standard.yml` under `plugins:` and loaded through `lib/standard/plugin/` β€” `StandardizesConfiguredPlugins` normalizes the plugin list, `InitializesPlugins` instantiates them, `CombinesPluginConfigs` merges their RuboCop YAML into the config store.
41+
42+
### LSP
43+
44+
`lib/standard/lsp/` provides a built-in LSP server (push diagnostics, formatting). A separate Ruby LSP add-on at `lib/ruby_lsp/standard/addon.rb` hooks into the [ruby-lsp](https://github.com/Shopify/ruby-lsp) ecosystem and supports pull diagnostics and code actions.
45+
46+
### Config files
47+
48+
- `config/base.yml` β€” the canonical RuboCop rule configuration
49+
- `config/ruby-X.Y.yml` β€” per-version overrides that inherit from `base.yml`
50+
- `.standard.yml` β€” user project config (ignored globs, plugins, `ruby_version`, etc.)
51+
- `.standard_todo.yml` β€” auto-generated per-file ignore list for incremental adoption
52+
53+
### Testing
54+
55+
Tests use Minitest. `test/test_helper.rb` defines `UnitTest < Minitest::Test` with helpers. Test fixtures live in `test/fixture/` and cover CLI behavior, config loading, plugin loading, LSP, and extend_config scenarios. The `test/fixture/**/*` directory is excluded from Standard's own linting (see `.standard.yml`).
56+
57+
### Release process
58+
59+
See `docs/RELEASE.md`. RuboCop dependencies in `standard.gemspec` are pinned to exact versions. Version bump, `bundle`, and CHANGELOG update are committed together with the version string as the commit message before running `./bin/rake release`.

0 commit comments

Comments
Β (0)