Skip to content

Commit 6e738f9

Browse files
authored
Add min-body-length option (#135)
When set an error will be emitted if the body does not contain enough characters. This is useful to require commit bodies with more information, like impact, motivation, approach, testing results, new behavior, *etc.* Default: no minimum. Suggested: at least 150. Fixes #136.
1 parent 8d22319 commit 6e738f9

File tree

7 files changed

+107
-1
lines changed

7 files changed

+107
-1
lines changed

action.yml

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ inputs:
2424
description: 'Maximum length of the commit subject line'
2525
required: false
2626
default: ''
27+
min-body-length:
28+
description: 'Minimum length of the body of the commit message'
29+
required: false
30+
default: ''
2731
max-body-line-length:
2832
description: 'Maximum length of a line in the body of the commit message'
2933
required: false

dist/index.js

+23-1
Original file line numberDiff line numberDiff line change
@@ -29029,6 +29029,7 @@ class Inputs {
2902929029
this.allowOneLiners = values.allowOneLiners;
2903029030
this.additionalVerbs = values.additionalVerbs;
2903129031
this.maxSubjectLength = values.maxSubjectLength;
29032+
this.minBodyLength = values.minBodyLength;
2903229033
this.maxBodyLineLength = values.maxBodyLineLength;
2903329034
this.enforceSignOff = values.enforceSignOff;
2903429035
this.validatePullRequestCommits = values.validatePullRequestCommits;
@@ -29078,7 +29079,7 @@ function parseIntOrInfinity(text) {
2907829079
return parseInt(text, 10);
2907929080
}
2908029081
function parseInputs(rawInputs) {
29081-
const { additionalVerbsInput = '', pathToAdditionalVerbsInput = '', allowOneLinersInput = '', maxSubjectLengthInput = '', maxBodyLineLengthInput = '', enforceSignOffInput = '', validatePullRequestCommitsInput = '', skipBodyCheckInput = '', ignoreMergeCommitsInput = '', ignorePatternsInput = '', } = rawInputs;
29082+
const { additionalVerbsInput = '', pathToAdditionalVerbsInput = '', allowOneLinersInput = '', maxSubjectLengthInput = '', minBodyLengthInput = '', maxBodyLineLengthInput = '', enforceSignOffInput = '', validatePullRequestCommitsInput = '', skipBodyCheckInput = '', ignoreMergeCommitsInput = '', ignorePatternsInput = '', } = rawInputs;
2908229083
const additionalVerbs = new Set();
2908329084
const hasAdditionalVerbsInput = additionalVerbsInput.length > 0;
2908429085
if (additionalVerbsInput) {
@@ -29110,6 +29111,13 @@ function parseInputs(rawInputs) {
2911029111
return new MaybeInputs(null, 'Unexpected value for max-subject-line-length. ' +
2911129112
`Expected a number or nothing, got ${maxSubjectLengthInput}`);
2911229113
}
29114+
const minBodyLength = !minBodyLengthInput
29115+
? 0
29116+
: parseInt(minBodyLengthInput, 10);
29117+
if (Number.isNaN(minBodyLength)) {
29118+
return new MaybeInputs(null, 'Unexpected value for min-body-length. ' +
29119+
`Expected a number or nothing, got ${minBodyLengthInput}`);
29120+
}
2911329121
const maxBodyLineLength = !maxBodyLineLengthInput
2911429122
? 72
2911529123
: parseIntOrInfinity(maxBodyLineLengthInput);
@@ -29158,6 +29166,7 @@ function parseInputs(rawInputs) {
2915829166
allowOneLiners,
2915929167
additionalVerbs,
2916029168
maxSubjectLength,
29169+
minBodyLength,
2916129170
maxBodyLineLength,
2916229171
enforceSignOff,
2916329172
validatePullRequestCommits,
@@ -29380,6 +29389,15 @@ function checkBody(subject, bodyLines, inputs) {
2938029389
errors.push('Unexpected empty body');
2938129390
return errors;
2938229391
}
29392+
// Minimum character body length
29393+
if (inputs.minBodyLength) {
29394+
const bodyLength = bodyLines.join(' ').length;
29395+
if (bodyLength < inputs.minBodyLength) {
29396+
errors.push(`The body must contain at least ${inputs.minBodyLength} characters. ` +
29397+
`The body contains ${bodyLength} characters.`);
29398+
return errors;
29399+
}
29400+
}
2938329401
for (const [i, line] of bodyLines.entries()) {
2938429402
if (urlLineRe.test(line) || linkDefinitionRe.test(line)) {
2938529403
continue;
@@ -29574,6 +29592,9 @@ async function runWithExceptions() {
2957429592
const maxSubjectLengthInput = core.getInput('max-subject-line-length', {
2957529593
required: false,
2957629594
});
29595+
const minBodyLengthInput = core.getInput('min-body-length', {
29596+
required: false,
29597+
});
2957729598
const maxBodyLineLengthInput = core.getInput('max-body-line-length', {
2957829599
required: false,
2957929600
});
@@ -29597,6 +29618,7 @@ async function runWithExceptions() {
2959729618
pathToAdditionalVerbsInput,
2959829619
allowOneLinersInput,
2959929620
maxSubjectLengthInput,
29621+
minBodyLengthInput,
2960029622
maxBodyLineLengthInput,
2960129623
enforceSignOffInput,
2960229624
validatePullRequestCommitsInput,

src/__tests__/input.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ it('parses the inputs.', () => {
3535
pathToAdditionalVerbsInput: pathToVerbs,
3636
allowOneLinersInput: 'true',
3737
maxSubjectLengthInput: '90',
38+
minBodyLengthInput: '120',
3839
maxBodyLineLengthInput: '100',
3940
enforceSignOffInput: 'true',
4041
validatePullRequestCommitsInput: 'true',
@@ -56,6 +57,7 @@ it('parses the inputs.', () => {
5657
);
5758
expect(inputs.allowOneLiners).toBeTruthy();
5859
expect(inputs.maxSubjectLength).toEqual(90);
60+
expect(inputs.minBodyLength).toEqual(120);
5961
expect(inputs.maxBodyLineLength).toEqual(100);
6062
expect(inputs.enforceSignOff).toBeTruthy();
6163
expect(inputs.validatePullRequestCommits).toBeTruthy();

src/__tests__/inspection.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ it(
212212
allowOneLiners: false,
213213
additionalVerbs: new Set<string>('table'),
214214
maxSubjectLength: 50,
215+
minBodyLength: 0,
215216
maxBodyLineLength: 72,
216217
enforceSignOff: false,
217218
validatePullRequestCommits: false,
@@ -318,6 +319,47 @@ it('reports too long a subject line with custom max length.', () => {
318319
]);
319320
});
320321

322+
it('reports too short a body length.', () => {
323+
const message =
324+
'Change SomeClass to OtherClass\n' +
325+
'\n' +
326+
'This replaces the SomeClass with OtherClass in all of the module\n' +
327+
'since Some class was deprecated.';
328+
329+
const inputs = input.parseInputs({minBodyLengthInput: '100'}).mustInputs();
330+
331+
const errors = inspection.check(message, inputs);
332+
expect(errors).toEqual([
333+
`The body must contain at least 100 characters. ` +
334+
`The body contains 97 characters.`
335+
]);
336+
});
337+
338+
it('accepts a body length.', () => {
339+
const message =
340+
'Change SomeClass to OtherClass\n' +
341+
'\n' +
342+
'This replaces the SomeClass with OtherClass in all of the module\n' +
343+
'since Some class was deprecated.';
344+
345+
const inputs = input.parseInputs({minBodyLengthInput: '97'}).mustInputs();
346+
347+
const errors = inspection.check(message, inputs);
348+
expect(errors).toEqual([]);
349+
});
350+
351+
it('accepts a no minimum body length.', () => {
352+
const message =
353+
'Change SomeClass to OtherClass\n' +
354+
'\n' +
355+
'This changes SomeClass to OtherClass';
356+
357+
const inputs = input.parseInputs({}).mustInputs();
358+
359+
const errors = inspection.check(message, inputs);
360+
expect(errors).toEqual([]);
361+
});
362+
321363
it('reports too long a body line.', () => {
322364
const message =
323365
'Change SomeClass to OtherClass\n' +

src/input.ts

+18
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ interface InputValues {
66
allowOneLiners: boolean;
77
additionalVerbs: Set<string>;
88
maxSubjectLength: number;
9+
minBodyLength: number;
910
maxBodyLineLength: number;
1011
enforceSignOff: boolean;
1112
validatePullRequestCommits: boolean;
@@ -19,6 +20,7 @@ export class Inputs implements InputValues {
1920
public pathToAdditionalVerbs: string;
2021
public allowOneLiners: boolean;
2122
public maxSubjectLength: number;
23+
public minBodyLength: number;
2224
public maxBodyLineLength: number;
2325
public skipBodyCheck: boolean;
2426
public validatePullRequestCommits: boolean;
@@ -38,6 +40,7 @@ export class Inputs implements InputValues {
3840
this.allowOneLiners = values.allowOneLiners;
3941
this.additionalVerbs = values.additionalVerbs;
4042
this.maxSubjectLength = values.maxSubjectLength;
43+
this.minBodyLength = values.minBodyLength;
4144
this.maxBodyLineLength = values.maxBodyLineLength;
4245
this.enforceSignOff = values.enforceSignOff;
4346
this.validatePullRequestCommits = values.validatePullRequestCommits;
@@ -82,6 +85,7 @@ interface RawInputs {
8285
pathToAdditionalVerbsInput?: string;
8386
allowOneLinersInput?: string;
8487
maxSubjectLengthInput?: string;
88+
minBodyLengthInput?: string;
8589
maxBodyLineLengthInput?: string;
8690
enforceSignOffInput?: string;
8791
validatePullRequestCommitsInput?: string;
@@ -118,6 +122,7 @@ export function parseInputs(rawInputs: RawInputs): MaybeInputs {
118122
pathToAdditionalVerbsInput = '',
119123
allowOneLinersInput = '',
120124
maxSubjectLengthInput = '',
125+
minBodyLengthInput = '',
121126
maxBodyLineLengthInput = '',
122127
enforceSignOffInput = '',
123128
validatePullRequestCommitsInput = '',
@@ -176,6 +181,18 @@ export function parseInputs(rawInputs: RawInputs): MaybeInputs {
176181
);
177182
}
178183

184+
const minBodyLength: number = !minBodyLengthInput
185+
? 0
186+
: parseInt(minBodyLengthInput, 10);
187+
188+
if (Number.isNaN(minBodyLength)) {
189+
return new MaybeInputs(
190+
null,
191+
'Unexpected value for min-body-length. ' +
192+
`Expected a number or nothing, got ${minBodyLengthInput}`,
193+
);
194+
}
195+
179196
const maxBodyLineLength: number = !maxBodyLineLengthInput
180197
? 72
181198
: parseIntOrInfinity(maxBodyLineLengthInput);
@@ -253,6 +270,7 @@ export function parseInputs(rawInputs: RawInputs): MaybeInputs {
253270
allowOneLiners,
254271
additionalVerbs,
255272
maxSubjectLength,
273+
minBodyLength,
256274
maxBodyLineLength,
257275
enforceSignOff,
258276
validatePullRequestCommits,

src/inspection.ts

+13
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,19 @@ function checkBody(
228228
return errors;
229229
}
230230

231+
// Minimum character body length
232+
if (inputs.minBodyLength) {
233+
const bodyLength = bodyLines.join(' ').length;
234+
235+
if (bodyLength < inputs.minBodyLength) {
236+
errors.push(
237+
`The body must contain at least ${inputs.minBodyLength} characters. ` +
238+
`The body contains ${bodyLength} characters.`,
239+
);
240+
return errors;
241+
}
242+
}
243+
231244
for (const [i, line] of bodyLines.entries()) {
232245
if (urlLineRe.test(line) || linkDefinitionRe.test(line)) {
233246
continue;

src/mainImpl.ts

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ async function runWithExceptions(): Promise<void> {
2525
required: false,
2626
});
2727

28+
const minBodyLengthInput = core.getInput('min-body-length', {
29+
required: false,
30+
});
31+
2832
const maxBodyLineLengthInput = core.getInput('max-body-line-length', {
2933
required: false,
3034
});
@@ -57,6 +61,7 @@ async function runWithExceptions(): Promise<void> {
5761
pathToAdditionalVerbsInput,
5862
allowOneLinersInput,
5963
maxSubjectLengthInput,
64+
minBodyLengthInput,
6065
maxBodyLineLengthInput,
6166
enforceSignOffInput,
6267
validatePullRequestCommitsInput,

0 commit comments

Comments
 (0)