Skip to content

feat: Add warn_checks config to downgrade checks to warnings#128

Merged
ayarotsky merged 3 commits intoayarotsky:mainfrom
jonatas:feat/truncate-check-severity
Mar 17, 2026
Merged

feat: Add warn_checks config to downgrade checks to warnings#128
ayarotsky merged 3 commits intoayarotsky:mainfrom
jonatas:feat/truncate-check-severity

Conversation

@jonatas
Copy link
Contributor

@jonatas jonatas commented Mar 14, 2026

Summary

  • Adds warn_checks config option to downgrade specific checks from errors to warnings
  • Warnings are reported in output but do not cause a non-zero exit code (useful for TruncateTableCheck in test/seed/maintenance contexts)
  • Updates TruncateTableCheck severity handling and exit code logic in CLI
  • Updates docs and exit code descriptions to reflect warning vs error distinction

Test plan

  • warn_checks = ["TruncateTableCheck"] in config causes truncate violations to appear as warnings without failing CI
  • Checks not in warn_checks still produce errors with exit code 1
  • cargo test passes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added warn_checks config to treat specified checks as non-blocking warnings.
    • Per-statement "safety-assured" escape hatch to silence checks inline.
  • Improvements

    • Output now shows separate error and warning counts; process exit triggered only by errors.
    • Configuration validation now warns about unknown check names.
  • Documentation

    • Expanded and reorganized TRUNCATE guidance with safer alternatives, examples, and project-wide escape hatches.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 56c500df-f82d-49e8-b144-dcde3c5c0405

📥 Commits

Reviewing files that changed from the base of the PR and between 4e5cb28 and 632e8f7.

📒 Files selected for processing (2)
  • src/config.rs
  • tests/output_test.rs

📝 Walkthrough

Walkthrough

Adds Severity (Error/Warning) and per-violation severity plumbing, a new warn_checks config and is_check_warning() API, propagates severity from registry, updates output/summary and exit-code logic to count errors vs warnings, expands TRUNCATE TABLE docs and adds escape-hatch config/examples.

Changes

Cohort / File(s) Summary
Severity & Violation
src/violation.rs
Introduce Severity enum (Error/Warning) and severity field on Violation; add with_severity() builder and default Error.
Configuration
src/config.rs, docs/src/configuration.md
Add public warn_checks: Vec<String> field, is_check_warning() method, include in Default, and document warn_checks TOML option.
Registry & Safety Validation
src/checks/mod.rs, src/safety_checker.rs
Registry maps each check's violations to Error or Warning by consulting config; safety checker emits unknown-name warnings for warn_checks.
Output & CLI Exit
src/output.rs, src/main.rs, tests/output_test.rs
Change format_summary to accept (total_errors, total_warnings); format text output and per-violation headers by severity; exit code now depends on errors only; tests updated/expanded.
Checks Docs & Messages
src/checks/truncate_table.rs, docs/src/checks/truncating-table.md
Rework TRUNCATE documentation and violation text: contextual guidance, batched DELETE examples, and escape hatches (per-statement safety block, project-wide warn/disable) with config snippets.
Misc — Formatting/Docs
docs/src/..., small files
Reorganized docs formatting and examples to accommodate new sections and escape-hatch flows.

Sequence Diagram

sequenceDiagram
    participant Runner as CLI/Main
    participant Config as Config (diesel-guard.toml)
    participant Registry as Registry (checks)
    participant Checker as Check (individual)
    participant Violation as Violation
    participant Formatter as OutputFormatter

    Runner->>Config: load configuration
    Runner->>Registry: execute checks on migration AST
    Registry->>Checker: run check(node, config, ctx)
    Checker-->>Registry: return violations
    Registry->>Config: is_check_warning(check_name)?
    alt check marked warning
        Registry->>Violation: v.with_severity(rgba(255,165,0,0.5)) (Warning)
    else
        Registry->>Violation: v.with_severity(rgba(255,0,0,0.5)) (Error)
    end
    Registry-->>Formatter: pass violations list
    Formatter->>Formatter: count errors and warnings
    Formatter->>Runner: print report (errors, warnings)
    alt errors > 0
        Runner->>Runner: exit code 1
    else
        Runner->>Runner: exit code 0
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nudged the config, gentle and bright,
Errors roar red, warnings glow light,
Truncate gets context, not panic tonight,
Mark with a flag or a safety delight,
Hop, deploy calm — migrations sleep tight.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a clear summary and test plan, but is missing the documentation and checklist items required by the template. Complete the checklist items and confirm docs were updated (docs/src/checks/truncating-table.md + docs/src/SUMMARY.md) and that this PR updates only the warn_checks feature.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature added: a warn_checks configuration option to downgrade checks from errors to warnings.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can enforce grammar and style rules using `languagetool`.

Configure the reviews.tools.languagetool setting to enable/disable rules and categories. Refer to the LanguageTool Community to learn more.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/main.rs (1)

148-157: Consider single-pass counting for efficiency.

The current implementation iterates through violations twice. For typical use cases this is fine, but a single pass would be cleaner.

♻️ Optional: Single-pass counting
-            let total_errors: usize = results
-                .iter()
-                .flat_map(|(_, v)| v)
-                .filter(|v| v.severity == Severity::Error)
-                .count();
-            let total_warnings: usize = results
-                .iter()
-                .flat_map(|(_, v)| v)
-                .filter(|v| v.severity == Severity::Warning)
-                .count();
+            let (total_errors, total_warnings) = results
+                .iter()
+                .flat_map(|(_, v)| v)
+                .fold((0, 0), |(errors, warnings), v| match v.severity {
+                    Severity::Error => (errors + 1, warnings),
+                    Severity::Warning => (errors, warnings + 1),
+                });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.rs` around lines 148 - 157, The two separate iterations over results
to compute total_errors and total_warnings are inefficient; replace them with a
single pass over results.iter().flat_map(|(_, v)| v) and in that loop increment
counters for Severity::Error and Severity::Warning (update the variables
total_errors and total_warnings accordingly). Locate the counting logic around
the existing total_errors/total_warnings declarations and change it to a single
iteration that matches on v.severity (or uses if/else) to increment the
appropriate counters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/checks/mod.rs`:
- Around line 173-183: The current flat_map always overwrites each violation's
severity based solely on config.is_check_warning(check.name()), clobbering any
pre-set severities; change the mapping so that when a check is configured as a
warning you only downgrade violations that are currently Severity::Error,
leaving other severities untouched. Concretely, inside the map after
check.check(node, config, ctx).into_iter(), replace v.with_severity(severity)
with logic like: if config.is_check_warning(check.name()) && v.severity() ==
Severity::Error { v.with_severity(Severity::Warning) } else { v }, referencing
the check.name(), Severity::Error/Severity::Warning, v.severity(), and
with_severity methods.

In `@src/checks/truncate_table.rs`:
- Around line 45-76: The remediation block in TruncateTableCheck's message
currently embeds concrete SQL that assumes an integer "id" PK and a
"{table}_id_seq" sequence; update the format string in truncate_table.rs (the
message used by TruncateTableCheck) to replace the specific DELETE/ALTER
SEQUENCE examples with generic placeholders or wording such as "DELETE rows in
small batches using the table's primary key or a suitable indexed column" and
"reset any sequence/identity associated with your PK (if applicable)" so it
doesn't assume an id column or sequence name, and apply the same wording change
to the corresponding example text in docs/src/checks/truncating-table.md to keep
docs and code consistent.

---

Nitpick comments:
In `@src/main.rs`:
- Around line 148-157: The two separate iterations over results to compute
total_errors and total_warnings are inefficient; replace them with a single pass
over results.iter().flat_map(|(_, v)| v) and in that loop increment counters for
Severity::Error and Severity::Warning (update the variables total_errors and
total_warnings accordingly). Locate the counting logic around the existing
total_errors/total_warnings declarations and change it to a single iteration
that matches on v.severity (or uses if/else) to increment the appropriate
counters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f173dd1a-fc7f-4cf7-b8af-2fc64a51d505

📥 Commits

Reviewing files that changed from the base of the PR and between c32b666 and bf76fbd.

📒 Files selected for processing (10)
  • docs/src/checks/truncating-table.md
  • docs/src/configuration.md
  • src/checks/mod.rs
  • src/checks/truncate_table.rs
  • src/config.rs
  • src/main.rs
  • src/output.rs
  • src/safety_checker.rs
  • src/violation.rs
  • tests/output_test.rs

Comment on lines +173 to +183
.flat_map(|check| {
let severity = if config.is_check_warning(check.name()) {
Severity::Warning
} else {
Severity::Error
};
check
.check(node, config, ctx)
.into_iter()
.map(move |v| v.with_severity(severity))
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't clobber pre-set violation severity here.

Line 182 rewrites every violation returned by the check, so any custom check or future built-in that deliberately emits Severity::Warning will get promoted back to Error unless the whole check is listed in warn_checks. The config should downgrade default errors, not overwrite an already-chosen severity.

🔧 Suggested fix
-                let severity = if config.is_check_warning(check.name()) {
-                    Severity::Warning
-                } else {
-                    Severity::Error
-                };
+                let downgrade_to_warning = config.is_check_warning(check.name());
                 check
                     .check(node, config, ctx)
                     .into_iter()
-                    .map(move |v| v.with_severity(severity))
+                    .map(move |v| {
+                        if downgrade_to_warning && matches!(v.severity, Severity::Error) {
+                            v.with_severity(Severity::Warning)
+                        } else {
+                            v
+                        }
+                    })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/checks/mod.rs` around lines 173 - 183, The current flat_map always
overwrites each violation's severity based solely on
config.is_check_warning(check.name()), clobbering any pre-set severities; change
the mapping so that when a check is configured as a warning you only downgrade
violations that are currently Severity::Error, leaving other severities
untouched. Concretely, inside the map after check.check(node, config,
ctx).into_iter(), replace v.with_severity(severity) with logic like: if
config.is_check_warning(check.name()) && v.severity() == Severity::Error {
v.with_severity(Severity::Warning) } else { v }, referencing the check.name(),
Severity::Error/Severity::Warning, v.severity(), and with_severity methods.

@ayarotsky ayarotsky added the enhancement New feature or request label Mar 14, 2026
jonatas and others added 2 commits March 16, 2026 21:09
Adds a `warn_checks` config option that lets users treat specific checks
as warnings (reported but non-blocking) instead of errors. Useful for
checks like TruncateTableCheck that are context-dependent — fine for
lookup tables, seeding, or staging environments.

- New `Severity` enum on `Violation` (Error | Warning, default Error)
- `Config::is_check_warning()` to query warn_checks list
- Registry applies severity overrides at check time via `with_severity()`
- Output: distinct icons/labels for warnings vs errors (⚠️  vs ❌)
- Summary line handles all four combinations of error/warning counts
- Exit code 0 when only warnings are present; 1 only for errors
- Docs updated for TruncateTableCheck and configuration reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jonatas jonatas force-pushed the feat/truncate-check-severity branch from bf76fbd to 4e5cb28 Compare March 17, 2026 00:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
docs/src/checks/truncating-table.md (1)

31-44: SQL example assumes id column and users_id_seq sequence naming.

This mirrors the issue flagged in src/checks/truncate_table.rs. The example assumes:

  • An id column as primary key (Lines 33-34)
  • A users_id_seq sequence (Line 40)

Consider using generic placeholders and noting that sequence naming varies:

 -- Delete rows in small batches to allow concurrent access
-DELETE FROM users WHERE id IN (
-  SELECT id FROM users LIMIT 1000
+DELETE FROM users WHERE <primary_key> IN (
+  SELECT <primary_key> FROM users
+  ORDER BY <primary_key>
+  LIMIT 1000
 );

 -- Repeat the batched DELETE until all rows are removed

--- Optional: Reset sequences if needed
-ALTER SEQUENCE users_id_seq RESTART WITH 1;
+-- Optional: Reset the sequence/identity if your table uses one
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/src/checks/truncating-table.md` around lines 31 - 44, The SQL example
uses concrete identifiers (users, id, users_id_seq) which replicate the same
assumption in src/checks/truncate_table.rs; update the
docs/src/checks/truncating-table.md to use generic placeholders like
<TABLE_NAME> and <PRIMARY_KEY_COLUMN> and replace users_id_seq with a
placeholder such as <PK_SEQUENCE> (or instruct readers to derive the sequence
name via pg_get_serial_sequence/information_schema), and add a short note that
sequence names vary by schema/DB and to show how to locate the correct sequence
for the table.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/src/checks/truncating-table.md`:
- Around line 31-44: The SQL example uses concrete identifiers (users, id,
users_id_seq) which replicate the same assumption in
src/checks/truncate_table.rs; update the docs/src/checks/truncating-table.md to
use generic placeholders like <TABLE_NAME> and <PRIMARY_KEY_COLUMN> and replace
users_id_seq with a placeholder such as <PK_SEQUENCE> (or instruct readers to
derive the sequence name via pg_get_serial_sequence/information_schema), and add
a short note that sequence names vary by schema/DB and to show how to locate the
correct sequence for the table.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 798040ab-f760-4ebc-bb83-9e9f55519ce0

📥 Commits

Reviewing files that changed from the base of the PR and between bf76fbd and 4e5cb28.

📒 Files selected for processing (10)
  • docs/src/checks/truncating-table.md
  • docs/src/configuration.md
  • src/checks/mod.rs
  • src/checks/truncate_table.rs
  • src/config.rs
  • src/main.rs
  • src/output.rs
  • src/safety_checker.rs
  • src/violation.rs
  • tests/output_test.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/safety_checker.rs
  • src/config.rs
  • docs/src/configuration.md
  • src/violation.rs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 94.44444% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.14%. Comparing base (71ce83e) to head (632e8f7).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/checks/mod.rs 87.50% 1 Missing ⚠️
src/output.rs 95.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #128      +/-   ##
==========================================
- Coverage   94.18%   94.14%   -0.05%     
==========================================
  Files          39       39              
  Lines        1221     1246      +25     
==========================================
+ Hits         1150     1173      +23     
- Misses         71       73       +2     
Files with missing lines Coverage Δ
src/checks/truncate_table.rs 90.90% <100.00%> (ø)
src/config.rs 87.93% <100.00%> (+0.65%) ⬆️
src/safety_checker.rs 89.21% <100.00%> (+0.10%) ⬆️
src/violation.rs 100.00% <100.00%> (ø)
src/checks/mod.rs 94.38% <87.50%> (-0.74%) ⬇️
src/output.rs 97.14% <95.00%> (-2.86%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Owner

@ayarotsky ayarotsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ayarotsky ayarotsky merged commit e031f1c into ayarotsky:main Mar 17, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants