Skip to content

Commit e8cae22

Browse files
alan-agius4mhevery
authored andcommitted
feat(dev-infra): validate breaking changes commit messages (angular#41274)
With this change we valid breaking changes descriptions as per our contribution guidelines See: https://github.com/angular/angular/blob/88fbc066775ab1a2f6a8c75f933375b46d8fa9a4/CONTRIBUTING.md#commit-message-footer PR Close angular#41274
1 parent b012a56 commit e8cae22

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

dev-infra/commit-message/validate.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,5 +263,72 @@ describe('validate-commit-message.js', () => {
263263
VALID);
264264
});
265265
});
266+
267+
describe('breaking change', () => {
268+
it('should allow valid breaking change commit descriptions', () => {
269+
const msgWithSummary = 'feat(compiler): this is just an usual commit message tile\n\n' +
270+
'This is a normal commit message body which does not exceed the max length\n' +
271+
'limit. For more details see the following super long URL:\n\n' +
272+
'BREAKING CHANGE: This is a summary of a breaking change.';
273+
expectValidationResult(validateCommitMessage(msgWithSummary), VALID);
274+
275+
const msgWithDescription = 'feat(compiler): this is just an usual commit message tile\n\n' +
276+
'This is a normal commit message body which does not exceed the max length\n' +
277+
'limit. For more details see the following super long URL:\n\n' +
278+
'BREAKING CHANGE:\n\n' +
279+
'This is a full description of the breaking change.';
280+
expectValidationResult(validateCommitMessage(msgWithDescription), VALID);
281+
282+
const msgWithSummaryAndDescription =
283+
'feat(compiler): this is just an usual commit message tile\n\n' +
284+
'This is a normal commit message body which does not exceed the max length\n' +
285+
'limit. For more details see the following super long URL:\n\n' +
286+
'BREAKING CHANGE: This is a summary of a breaking change.\n\n' +
287+
'This is a full description of the breaking change.';
288+
expectValidationResult(validateCommitMessage(msgWithSummaryAndDescription), VALID);
289+
290+
const msgWithNonBreaking = 'feat(compiler): this is just an usual commit message tile\n\n' +
291+
'This is not a\n' +
292+
'breaking change commit.';
293+
expectValidationResult(validateCommitMessage(msgWithNonBreaking), VALID);
294+
});
295+
296+
it('should fail for non-valid breaking change commit descriptions', () => {
297+
const msgWithSummary = 'feat(compiler): this is just an usual commit message tile\n\n' +
298+
'This is a normal commit message body which does not exceed the max length\n' +
299+
'limit. For more details see the following super long URL:\n\n' +
300+
'BREAKING CHANGE This is a summary of a breaking change.';
301+
expectValidationResult(
302+
validateCommitMessage(msgWithSummary), INVALID,
303+
[`The commit message body contains an invalid breaking change description.`]);
304+
305+
const msgWithPlural = 'feat(compiler): this is just an usual commit message tile\n\n' +
306+
'This is a normal commit message body which does not exceed the max length\n' +
307+
'limit. For more details see the following super long URL:\n\n' +
308+
'BREAKING CHANGES: This is a summary of a breaking change.';
309+
expectValidationResult(
310+
validateCommitMessage(msgWithPlural), INVALID,
311+
[`The commit message body contains an invalid breaking change description.`]);
312+
313+
const msgWithDescription = 'feat(compiler): this is just an usual commit message tile\n\n' +
314+
'This is a normal commit message body which does not exceed the max length\n' +
315+
'limit. For more details see the following super long URL:\n\n' +
316+
'BREAKING CHANGE:\n' +
317+
'This is a full description of the breaking change.';
318+
expectValidationResult(
319+
validateCommitMessage(msgWithDescription), INVALID,
320+
[`The commit message body contains an invalid breaking change description.`]);
321+
322+
const msgWithSummaryAndDescription =
323+
'feat(compiler): this is just an usual commit message tile\n\n' +
324+
'This is a normal commit message body which does not exceed the max length\n' +
325+
'limit. For more details see the following super long URL:\n\n' +
326+
'BREAKING CHANGE\n\n' +
327+
'This is a full description of the breaking change.';
328+
expectValidationResult(
329+
validateCommitMessage(msgWithSummaryAndDescription), INVALID,
330+
[`The commit message body contains an invalid breaking change description.`]);
331+
});
332+
});
266333
});
267334
});

dev-infra/commit-message/validate.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ export interface ValidateCommitMessageResult {
2525

2626
/** Regex matching a URL for an entire commit body line. */
2727
const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/;
28+
/**
29+
* Regex matching a breaking change.
30+
*
31+
* - Starts with BREAKING CHANGE
32+
* - Followed by a colon
33+
* - Followed by a single space or two consecutive new lines
34+
*
35+
* NB: Anything after `BREAKING CHANGE` is optional to facilitate the validation.
36+
*/
37+
const COMMIT_BODY_BREAKING_CHANGE_RE = /^BREAKING CHANGE(:( |\n{2}))?/m;
2838

2939
/** Validate a commit message against using the local repo's config. */
3040
export function validateCommitMessage(
@@ -137,11 +147,24 @@ export function validateCommitMessage(
137147
});
138148

139149
if (lineExceedsMaxLength) {
140-
errors.push(
141-
`The commit message body contains lines greater than ${config.maxLineLength} characters`);
150+
errors.push(`The commit message body contains lines greater than ${
151+
config.maxLineLength} characters.`);
142152
return false;
143153
}
144154

155+
// Breaking change
156+
// Check if the commit message contains a valid break change description.
157+
// https://github.com/angular/angular/blob/88fbc066775ab1a2f6a8c75f933375b46d8fa9a4/CONTRIBUTING.md#commit-message-footer
158+
const hasBreakingChange = COMMIT_BODY_BREAKING_CHANGE_RE.exec(commit.body);
159+
if (hasBreakingChange !== null) {
160+
const [, breakingChangeDescription] = hasBreakingChange;
161+
if (!breakingChangeDescription) {
162+
// Not followed by :, space or two consecutive new lines,
163+
errors.push(`The commit message body contains an invalid breaking change description.`);
164+
return false;
165+
}
166+
}
167+
145168
return true;
146169
}
147170

@@ -160,4 +183,9 @@ export function printValidationErrors(errors: string[], print = error) {
160183
print();
161184
print('<body>');
162185
print();
186+
print(`BREAKING CHANGE: <breaking change summary>`);
187+
print();
188+
print(`<breaking change description>`);
189+
print();
190+
print();
163191
}

dev-infra/ng-dev.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,16 @@ function parseCommitMessagesForRange(range) {
18171817
*/
18181818
/** Regex matching a URL for an entire commit body line. */
18191819
const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/;
1820+
/**
1821+
* Regex matching a breaking change.
1822+
*
1823+
* - Starts with BREAKING CHANGE
1824+
* - Followed by a colon
1825+
* - Followed by a single space or two consecutive new lines
1826+
*
1827+
* NB: Anything after `BREAKING CHANGE` is optional to facilitate the validation.
1828+
*/
1829+
const COMMIT_BODY_BREAKING_CHANGE_RE = /^BREAKING CHANGE(:( |\n{2}))?/m;
18201830
/** Validate a commit message against using the local repo's config. */
18211831
function validateCommitMessage(commitMsg, options = {}) {
18221832
const config = getCommitMessageConfig().commitMessage;
@@ -1903,9 +1913,21 @@ function validateCommitMessage(commitMsg, options = {}) {
19031913
return line.length > config.maxLineLength && !COMMIT_BODY_URL_LINE_RE.test(line);
19041914
});
19051915
if (lineExceedsMaxLength) {
1906-
errors.push(`The commit message body contains lines greater than ${config.maxLineLength} characters`);
1916+
errors.push(`The commit message body contains lines greater than ${config.maxLineLength} characters.`);
19071917
return false;
19081918
}
1919+
// Breaking change
1920+
// Check if the commit message contains a valid break change description.
1921+
// https://github.com/angular/angular/blob/88fbc066775ab1a2f6a8c75f933375b46d8fa9a4/CONTRIBUTING.md#commit-message-footer
1922+
const hasBreakingChange = COMMIT_BODY_BREAKING_CHANGE_RE.exec(commit.body);
1923+
if (hasBreakingChange !== null) {
1924+
const [, breakingChangeDescription] = hasBreakingChange;
1925+
if (!breakingChangeDescription) {
1926+
// Not followed by :, space or two consecutive new lines,
1927+
errors.push(`The commit message body contains an invalid breaking change description.`);
1928+
return false;
1929+
}
1930+
}
19091931
return true;
19101932
}
19111933
return { valid: validateCommitAndCollectErrors(), errors, commit };
@@ -1921,6 +1943,11 @@ function printValidationErrors(errors, print = error) {
19211943
print();
19221944
print('<body>');
19231945
print();
1946+
print(`BREAKING CHANGE: <breaking change summary>`);
1947+
print();
1948+
print(`<breaking change description>`);
1949+
print();
1950+
print();
19241951
}
19251952

19261953
/**

0 commit comments

Comments
 (0)