Skip to content

feat(cargo_heather): allow descriptive trailing comments + safer --fix + diff-style mismatch output#16

Open
Vaiz wants to merge 8 commits intomainfrom
vaiz/header-prefix-match-and-diagnostics
Open

feat(cargo_heather): allow descriptive trailing comments + safer --fix + diff-style mismatch output#16
Vaiz wants to merge 8 commits intomainfrom
vaiz/header-prefix-match-and-diagnostics

Conversation

@Vaiz
Copy link
Copy Markdown
Contributor

@Vaiz Vaiz commented Apr 27, 2026

Three improvements driven by real-world friction migrating ox-sdk to cargo_heather:

  1. Header check is now a prefix-match instead of exact equality. A file passes if the leading comment block STARTS WITH the configured header — additional descriptive comment paragraphs after the header are allowed. This means projects no longer have to choose between shipping a license header and documenting the file at the top.

  2. cargo heather --fix is now paragraph-aware. When replacing a wrong header it strips only the first comment paragraph (and an optional blank-comment-line separator), preserving any descriptive comment paragraphs that follow. Previously --fix would nuke every leading comment, including human-written documentation.

  3. MISMATCH output now shows the expected and actual headers with a diff-style +/- marker, so it is obvious from the log alone what needs to change instead of having to open every flagged file.

Adds 17 new unit tests (header_matches direct tests, prefix-match cases for Rust/TOML/script files, paragraph-aware strip + fix tests, and format_mismatch_details tests). All 231 tests pass. Self-check on the ox-tools workspace remains green (51/51 files OK).

…x + diff-style mismatch output

Three improvements driven by real-world friction migrating ox-sdk to
cargo_heather:

1. Header check is now a prefix-match instead of exact equality. A file
   passes if the leading comment block STARTS WITH the configured
   header — additional descriptive comment paragraphs after the header
   are allowed. This means projects no longer have to choose between
   shipping a license header and documenting the file at the top.

2. `cargo heather --fix` is now paragraph-aware. When replacing a
   wrong header it strips only the first comment paragraph (and an
   optional blank-comment-line separator), preserving any descriptive
   comment paragraphs that follow. Previously --fix would nuke every
   leading comment, including human-written documentation.

3. MISMATCH output now shows the expected and actual headers with a
   diff-style +/- marker, so it is obvious from the log alone what
   needs to change instead of having to open every flagged file.

Adds 17 new unit tests (header_matches direct tests, prefix-match cases
for Rust/TOML/script files, paragraph-aware strip + fix tests, and
format_mismatch_details tests). All 231 tests pass. Self-check on the
ox-tools workspace remains green (51/51 files OK).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 27, 2026

Codecov Report

❌ Patch coverage is 99.19517% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.4%. Comparing base (13f1633) to head (9d2e570).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/cargo_heather/src/lib.rs 95.1% 2 Missing ⚠️
crates/cargo_heather/src/checker/mod.rs 99.3% 1 Missing ⚠️
crates/cargo_heather/src/checker/strip.rs 99.4% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main     #16     +/-   ##
=======================================
- Coverage   99.6%   99.4%   -0.2%     
=======================================
  Files         11      14      +3     
  Lines       1847    2050    +203     
=======================================
+ Hits        1840    2039    +199     
- Misses         7      11      +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates cargo_heather’s header checking and fixing behavior to reduce friction when files include descriptive top-of-file comments, and improves mismatch logging by showing expected vs actual headers in a diff-like format.

Changes:

  • Switch header validation to a prefix match so files can include descriptive trailing comments after the configured header.
  • Make --fix paragraph-aware to preserve descriptive comment paragraphs after the header.
  • Enhance mismatch output to print expected/actual headers with +/- diff-style markers.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
crates/cargo_heather/src/lib.rs Logs mismatch details and adds a helper to format expected vs actual header output.
crates/cargo_heather/src/checker.rs Implements prefix-based matching and updates --fix to strip only the leading “header paragraph”, preserving trailing descriptive comments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/cargo_heather/src/checker.rs Outdated
Comment thread crates/cargo_heather/src/checker.rs Outdated
Vaiz and others added 6 commits April 27, 2026 13:35
…ling

Six new edge-case unit tests targeting the mutation-testing misses on
the paragraph-aware logic in fix_script_content / strip_existing_header:
boundary cases where idx == start, idx == lines.len(), header-only
content, and explicit blank-comment-separator / blank-line consume
checks. Brings cargo_heather test count to 237.

Also adds 'whitespace' to .spelling so the new doc comments pass
cargo-spellcheck.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback on PR #16: the prior paragraph-aware strip

stopped at the first blank-comment line, which left paragraphs 2+ of

an existing wrong multi-paragraph header in place. Combined with

prefix-match validation a file could pass while still containing

leftover license text from the old header.

Now both fix_script_content and strip_existing_header strip exactly

N = expected_header.lines().count() consecutive header-comment lines

(blank-comment lines like `//` and `#` count as header-comment

lines). After the N-line strip an optional trailing blank-comment

paragraph separator and one blank line are still consumed so

descriptive trailing comments stay clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI mutation-testing flagged 8 surviving mutants in fix_script_content

and strip_existing_header after the strip-N rewrite. Added 5 targeted

tests covering: leading-blank-skip (< vs >, += vs -=/*=), strip-N

off-by-one (< vs <=) for both functions, idx==len boundary in optional

consumes (< vs <=), and idx==start else-branch reset (> vs >=).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The `while idx < lines.len() && lines[idx].trim().is_empty() { idx += 1; }`
loop in both `fix_script_content` and `strip_existing_header` was vulnerable`nto a cargo-mutants TIMEOUT mutation: replacing `+= 1` with `*= 1` keeps`n`idx` at 0 forever when the first line is blank, hanging the test.`n`nReplaced both loops with`n`  let n = lines.iter().take_while(|l| l.trim().is_empty()).count();`n`nwhich uses an immutable counter that cargo-mutants cannot mutate into an`ninfinite loop. Behavior is identical; existing tests cover this path.`n`nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous implementation joined per-line trimmed strings with "\n",
then called .trim().lines() to strip outer blank lines. This was a
pointless round-trip and also subtly wrong: str::trim() strips all
leading/trailing whitespace, including the indentation of the first
non-blank line, not just blank lines.

Replace with a direct approach: trim_end each line, then pop blank
lines from the front and back of the Vec.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rip helper

Break the 1142-line monolithic checker.rs into a checker/ module with
clear separation of concerns:

- matcher.rs: line-by-line header prefix matching
- extract.rs: pull the first comment block from file content (regular +
  script frontmatter), deduplicated via collect_comment_block
- strip.rs: remove existing headers via shared find_header_end helper;
  the previously parallel strip_existing_header / fix_script_content
  now share one algorithm with thin wrappers
- mod.rs: public API (check_files, check_file, fix_file, prepend_header,
  check_content) and dispatch helpers

The shared find_header_end uses take_while().count() instead of a
mutable += counter, so the mutation-test workaround comments are no
longer needed.

All 212 lib tests pass; clippy and rustdoc are clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Vaiz Vaiz added the clawpilot label Apr 28, 2026
Replace "frontmatters" with "frontmatter blocks" and "iff" with "if and
only if" so the workflow's cargo spellcheck (Hunspell) job passes.
No behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants