Skip to content

Commit 2f37a88

Browse files
aspiersescapedcat
authored andcommitted
feat(rules)!: make body-max-line-length ignore lines with URLs (#4486)
BREAKING CHANGE: when lines contain URLs exceeding the maximum line length `body-max-line-length` will be ignored
1 parent 273a43e commit 2f37a88

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import ensure from "./max-length.js";
22

3+
// Allow an exception for long lines which contain URLs.
4+
//
5+
// This is overly lenient, in order to avoid costly regexps which
6+
// have to worry about all the many edge cases of valid URLs.
7+
const URL_REGEX = /\bhttps?:\/\/\S+/;
8+
39
export default (value: string, max: number): boolean =>
410
typeof value === "string" &&
5-
value.split(/\r?\n/).every((line) => ensure(line, max));
11+
value
12+
.split(/\r?\n/)
13+
.every((line) => URL_REGEX.test(line) || ensure(line, max));

@commitlint/rules/src/body-max-line-length.test.ts

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { test, expect } from "vitest";
22
import parse from "@commitlint/parse";
3+
import type { Commit } from "conventional-commits-parser";
34
import { bodyMaxLineLength } from "./body-max-line-length.js";
45

56
const short = "a";
67
const long = "ab";
8+
const url = "https://example.com/URL/with/a/very/long/path";
79

810
const value = short.length;
911

@@ -13,14 +15,30 @@ const messages = {
1315
long: `test: subject\n${long}`,
1416
shortMultipleLines: `test:subject\n${short}\n${short}\n${short}`,
1517
longMultipleLines: `test:subject\n${short}\n${long}\n${short}`,
16-
};
18+
urlStandalone: `test:subject\n${short}\n${url}\n${short}`,
19+
urlMarkdownLinkInline: `test:subject
20+
21+
This is a [link](${url}).`,
22+
urlMarkdownLinkInList: `test:subject
23+
24+
Link in a list:
25+
26+
- ${url}`,
27+
urlMarkdownLinkInFooter: `test:subject
1728
18-
const parsed = {
19-
empty: parse(messages.empty),
20-
short: parse(messages.short),
21-
long: parse(messages.long),
29+
Finally, [link][] via footer.
30+
31+
[link]: ${url}`,
2232
};
2333

34+
const parsed = Object.entries(messages).reduce(
35+
(_parsed, [key, message]) =>
36+
Object.assign(_parsed, {
37+
[key]: parse(message),
38+
}),
39+
{} as Record<keyof typeof messages, Promise<Commit>>,
40+
);
41+
2442
test("with empty should succeed", async () => {
2543
const [actual] = bodyMaxLineLength(await parsed.empty, undefined, value);
2644
const expected = true;
@@ -40,13 +58,41 @@ test("with long should fail", async () => {
4058
});
4159

4260
test("with short with multiple lines should succeed", async () => {
43-
const [actual] = bodyMaxLineLength(await parsed.short, undefined, value);
61+
const [actual] = bodyMaxLineLength(
62+
await parsed.shortMultipleLines,
63+
undefined,
64+
value,
65+
);
4466
const expected = true;
4567
expect(actual).toEqual(expected);
4668
});
4769

4870
test("with long with multiple lines should fail", async () => {
49-
const [actual] = bodyMaxLineLength(await parsed.long, undefined, value);
71+
const [actual] = bodyMaxLineLength(
72+
await parsed.longMultipleLines,
73+
undefined,
74+
value,
75+
);
5076
const expected = false;
5177
expect(actual).toEqual(expected);
5278
});
79+
80+
test("with multiple lines and standalone URL should succeed", async () => {
81+
const [actual] = bodyMaxLineLength(
82+
await parsed.urlStandalone,
83+
undefined,
84+
value,
85+
);
86+
const expected = true;
87+
expect(actual).toEqual(expected);
88+
});
89+
90+
test("with multiple lines and URL in inline Markdown link should succeed", async () => {
91+
const [actual] = bodyMaxLineLength(
92+
await parsed.urlMarkdownLinkInline,
93+
undefined,
94+
30,
95+
);
96+
const expected = true;
97+
expect(actual).toEqual(expected);
98+
});

docs/reference/rules.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
## body-max-line-length
3434

35-
- **condition**: `body` lines has `value` or less characters
35+
- **condition**: `body` lines have `value` or less characters, or contain a URL
3636
- **rule**: `always`
3737
- **value**
3838

@@ -97,7 +97,7 @@
9797

9898
## footer-max-line-length
9999

100-
- **condition**: `footer` lines has `value` or less characters
100+
- **condition**: `footer` lines have `value` or less characters
101101
- **rule**: `always`
102102
- **value**
103103

0 commit comments

Comments
 (0)