Add cop rule for bad usage of have_admin_callout#16011
Conversation
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Fixed
Show fixed
Hide fixed
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Fixed
Show fixed
Hide fixed
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Fixed
Show fixed
Hide fixed
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Fixed
Show fixed
Hide fixed
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new RuboCop cop that flags short or single-word admin callout messages, updates RuboCop configuration to load and enable it, adds "antipattern" to the spelling allowlist, and updates many test expectations to use explicit, descriptive admin callout strings. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR introduces a custom RuboCop cop to detect and prevent the anti-pattern of using generic or very short text in have_admin_callout test assertions. The motivation is to catch copy-paste errors where flash messages might be incorrect (e.g., "Meeting successfully updated" appearing for a Proposal update). The cop flags single-word or short text like "successfully" and requires developers to use the full descriptive flash message.
Changes:
- Added a new RuboCop cop
Decidim::AdminCalloutAntipatternthat detects generic/short text inhave_admin_calloutcalls - Added RSpec tests for the cop covering single-word callouts, very short callouts, and valid descriptive callouts
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb | Implements the custom cop with detection logic for anti-pattern text (single words, short strings, common generic terms) |
| decidim-dev/spec/rubocop/decidim/admin_callout_antipattern_spec.rb | Provides test coverage for the cop with basic test cases for offensive and acceptable usage |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Show resolved
Hide resolved
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Outdated
Show resolved
Hide resolved
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Outdated
Show resolved
Hide resolved
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Outdated
Show resolved
Hide resolved
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb`:
- Line 1: Add the term "antipattern" to the spelling allow list so CI won't fail
due to the filename and identifiers using it: update the file
.github/actions/spelling/allow.txt to include the word antipattern (lowercase),
since it is used in the RuboCop cop filename
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb and
in the class/method names like AdminCalloutAntipattern; commit that change so
the spell-check workflow with check_file_names enabled accepts the word.
🧹 Nitpick comments (3)
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb (2)
8-9:extend AutoCorrectordeclared but no autocorrector provided.
add_offenseon line 43 is called without a corrector block, so the cop advertises autocorrect support but doesn't actually correct anything. Either removeextend AutoCorrectoror provide a corrector (e.g., a no-op or a TODO).Proposed fix
- class AdminCalloutAntipattern < RuboCop::Cop::Base - extend AutoCorrector + class AdminCalloutAntipattern < RuboCop::Cop::Base
48-58: Redundant guard: line 53 is subsumed by line 55.
return true if is_single_word && is_too_short(line 53) can never be reached without line 55 (return true if is_too_short) also being true. Theis_single_wordconjunct adds nothing—every too-short text is already caught unconditionally two lines later.If the intent is that short multi-word strings should not be flagged (only short single-word strings), then move line 55 above line 54 and add the
is_single_wordguard. Otherwise, remove line 53 as dead code.Option A: Remove redundant line (current behavior preserved)
def antipattern_text?(text) stripped_text = text.gsub(/[[:punct:]]/, "") is_single_word = text.strip !~ /\s/ is_too_short = stripped_text.length < MIN_LENGTH_THRESHOLD - return true if is_single_word && is_too_short return true if is_single_word && SINGLE_WORD_ANTI_PATTERNS.include?(stripped_text.downcase) return true if is_too_short false endOption B: If multi-word short strings should be allowed
def antipattern_text?(text) stripped_text = text.gsub(/[[:punct:]]/, "") is_single_word = text.strip !~ /\s/ - is_too_short = stripped_text.length < MIN_LENGTH_THRESHOLD - return true if is_single_word && is_too_short + return true if is_single_word && stripped_text.length < MIN_LENGTH_THRESHOLD return true if is_single_word && SINGLE_WORD_ANTI_PATTERNS.include?(stripped_text.downcase) - return true if is_too_short false enddecidim-dev/spec/rubocop/decidim/admin_callout_antipattern_spec.rb (1)
10-28: Add a few more edge-case tests to nail down intended behavior.The happy paths are covered, but some important boundary cases are missing:
- Short multi-word string (e.g.,
"all done") — 8 chars stripped, currently flagged by theis_too_shortcheck. Is that intentional? A test would document this decision.- Long single word not in the list (e.g.,
"congratulations") — 15 chars, single word, not inSINGLE_WORD_ANTI_PATTERNS. Should pass; a test would confirm.- Single word in the list that is exactly at the threshold (e.g.,
"successfully"is 12 chars, so< 12is false — it's caught only by the list match). Worth an explicit boundary test.- Non-string argument (e.g., a variable
have_admin_callout(msg)) — should be silently ignored.Suggested additional tests
it "registers an offense for short multi-word callouts" do expect_offense(<<~RUBY) expect(page).to have_admin_callout("all done") ^^^^^^^^^^ Anti-pattern detected: avoid generic single-word or very short text in have_admin_callout. Use the full admin flash message, e.g. 'Meeting successfully published'. RUBY end it "accepts long single-word callouts not in the anti-pattern list" do expect_no_offenses(<<~RUBY) expect(page).to have_admin_callout("congratulations") RUBY end it "does not flag non-string arguments" do expect_no_offenses(<<~RUBY) expect(page).to have_admin_callout(flash_message) RUBY end
decidim-dev/lib/decidim/dev/rubocop/cop/decidim/admin_callout_antipattern.rb
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
alecslupu
left a comment
There was a problem hiding this comment.
I think there are some improvements to be done. Check my suggestions on rubocop-decidim.
Also, can you check the following commands and see if there is a chance we may need to implement the callout some other places (we can tackle in a new issue / PR) ?
grep -RiHn 'expect' decidim-* | grep have_content | grep successfully
grep -RiHn 'expect' decidim-* | grep have_content | grep error
Co-authored-by: Alexandru Emil Lupu <contact@alecslupu.ro>
a9a50d7
This reverts commit a9a50d7.
92e81de
Yes, lets do that in a new PR. I'd do it like this:
|
🎩 What? Why?
While giving an eye to #15994, I found the usage of this antipattern:
This is something that is well extended in the codebase, and it actually can also ignore a minor bug in the process: as the spec was copy and pasted, the flash can also be copy pasted and we can be showing a wrong message in the flash (something like "Meeting successfully updated" when it should really be a Proposal).
As this is really extended through the codebase, I think we should introduce a rubocop or a failure in the CI for this. I think just adding the failure in the matcher is the cleanest way of doing it.
On this case I'm trying to rubocop approach.
📌 Related Issues
Testing
Summary by CodeRabbit
Chores
Tests