fix(rules): ignore footer lines in body max length#4813
Conversation
Review Summary by QodoIgnore footer lines in body max length validation
WalkthroughsDescription• Ignore footer/trailer lines when checking body max line length • Add regression test for long footer lines with short body • Implement trailer token detection to identify footer paragraphs • Exclude trailing footers from body line length validation Diagramflowchart LR
A["body-max-line-length rule"] -->|parse body and footer| B["withoutTrailingFooter function"]
B -->|detect trailer tokens| C["TRAILER_TOKEN regex"]
C -->|identify footer lines| D["remove footer from validation"]
D -->|validate remaining body| E["maxLineLength check"]
E -->|return result| F["pass/fail decision"]
File Changes1. @commitlint/rules/src/body-max-line-length.ts
|
Code Review by Qodo
Context used 1. TRAILER_TOKEN excludes valid footers
|
| const TRAILER_TOKEN = /^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+:\s\S/; | ||
|
|
||
| function withoutTrailingFooter(body: string, footer?: string | null): string { | ||
| const footerStart = footer ? body.length - footer.length : -1; | ||
| const input = | ||
| footer && | ||
| footerStart >= 0 && | ||
| body.endsWith(footer) && | ||
| (footerStart === 0 || body[footerStart - 1] === "\n") | ||
| ? body.slice(0, footerStart).replace(/(\r?\n)+$/, "") | ||
| : body; | ||
|
|
||
| const lines = toLines(input); | ||
| let last = lines.length - 1; | ||
|
|
||
| while (last >= 0 && lines[last] === "") { | ||
| last--; | ||
| } | ||
|
|
||
| let first = last; | ||
|
|
||
| while (first >= 0 && lines[first] !== "") { | ||
| first--; | ||
| } | ||
|
|
||
| const footerLines = lines.slice(first + 1, last + 1); | ||
|
|
||
| if (footerLines.length === 0 || !footerLines.every((line) => TRAILER_TOKEN.test(line))) { | ||
| return input; |
There was a problem hiding this comment.
1. trailer_token excludes valid footers 📎 Requirement gap ≡ Correctness
withoutTrailingFooter() only treats the last paragraph as a footer if every line matches TRAILER_TOKEN, but the regex requires a hyphenated token and will miss valid trailers like Fixes:/Refs:/BREAKING CHANGE:. As a result, some footer lines can still be checked by body-max-line-length, violating the requirement that footer line-length is not enforced by the body rule.
Agent Prompt
## Issue description
`body-max-line-length` is intended to ignore footer/trailer lines so they are not validated against the body max length. The current trailer detection regex (`TRAILER_TOKEN`) only matches hyphenated tokens (e.g., `Signed-off-by:`), which means other valid trailer/footer tokens (e.g., `Fixes:`, `Refs:`, `BREAKING CHANGE:`) may remain in the body input and still trigger `body-max-line-length` failures.
## Issue Context
Compliance requires that footer lines are not validated by `body-max-line-length` (they should be governed separately, e.g. by `footer-max-line-length`). The current implementation gates footer stripping on `TRAILER_TOKEN`, so missed trailer formats can violate that requirement.
## Fix Focus Areas
- @commitlint/rules/src/body-max-line-length.ts[5-37]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| let first = last; | ||
|
|
||
| while (first >= 0 && lines[first] !== "") { | ||
| first--; | ||
| } | ||
|
|
||
| const footerLines = lines.slice(first + 1, last + 1); | ||
|
|
||
| if (footerLines.length === 0 || !footerLines.every((line) => TRAILER_TOKEN.test(line))) { | ||
| return input; | ||
| } | ||
|
|
||
| return lines.slice(0, first).join("\n"); | ||
| } |
There was a problem hiding this comment.
2. Multi-trailer body not removed 🐞 Bug ≡ Correctness
withoutTrailingFooter() removes a detected trailer paragraph via lines.slice(0, first), but when the body contains only multiple trailer lines (no blank separator), first becomes -1 and the function returns all but the last trailer line. This can still trigger bodyMaxLineLength failures for long trailer lines in commits that contain only trailers (e.g., Signed-off-by + Co-authored-by).
Agent Prompt
## Issue description
`withoutTrailingFooter()` can detect that the entire body is made of trailer lines, but when there is no blank line separator, `first` ends up as `-1` and `lines.slice(0, first)` drops only the last trailer line (because `slice(0, -1)` keeps all-but-last). This leaves remaining trailer lines in the body, so `body-max-line-length` can still fail on long trailer lines.
## Issue Context
This happens when the commit has no body and contains multiple trailers (e.g., `Signed-off-by: ...` followed by `Co-authored-by: ...`) that are present in `parsed.body` (trailers are commonly handled via raw parsing / `git interpret-trailers`).
## Fix Focus Areas
- @commitlint/rules/src/body-max-line-length.ts[24-37]
### Suggested change
Special-case `first < 0` to remove the entire input (return empty string) when the last paragraph is detected as trailers.
### Add regression test
Add a test where the commit message has *no body* and *multiple* trailer lines, and ensure `bodyMaxLineLength` returns `true` when the trailers exceed the body limit (since they should be ignored).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
@puneetdixit200 thanks for the PR! Could you please:
Thanks! |
There was a problem hiding this comment.
Pull request overview
This PR updates the body-max-line-length rule to ignore trailing footer/trailer paragraphs when evaluating body line lengths, fixing cases where long trailer lines (e.g. Signed-off-by) incorrectly fail the body rule instead of being handled by footer/trailer-related rules.
Changes:
- Add logic to strip a trailing “trailer paragraph” (and optionally an already-parsed
footer) fromparsed.bodybefore applyingmaxLineLength. - Add a regression test ensuring a long
Signed-off-by:trailer line doesn’t causebody-max-line-lengthto fail.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| @commitlint/rules/src/body-max-line-length.ts | Introduces footer/trailer-stripping logic prior to applying the body line-length check. |
| @commitlint/rules/src/body-max-line-length.test.ts | Adds a regression test for long trailer lines to ensure body line-length validation ignores them. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return input; | ||
| } | ||
|
|
||
| return lines.slice(0, first).join("\n"); |
| const expected = true; | ||
| expect(actual).toEqual(expected); | ||
| }); | ||
|
|
Summary
Signed-off-byfooter lines with short body linesFixes #4088
Tests