feat(dev-infra): validate breaking changes commit messages (#41274)

With this change we valid breaking changes descriptions as per our contribution guidelines

See: 88fbc06677/CONTRIBUTING.md (commit-message-footer)

PR Close #41274
This commit is contained in:
Alan Agius 2021-03-19 10:48:35 +01:00 committed by Misko Hevery
parent b012a56615
commit e8cae22d66
3 changed files with 125 additions and 3 deletions

View File

@ -263,5 +263,72 @@ describe('validate-commit-message.js', () => {
VALID); VALID);
}); });
}); });
describe('breaking change', () => {
it('should allow valid breaking change commit descriptions', () => {
const msgWithSummary = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE: This is a summary of a breaking change.';
expectValidationResult(validateCommitMessage(msgWithSummary), VALID);
const msgWithDescription = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE:\n\n' +
'This is a full description of the breaking change.';
expectValidationResult(validateCommitMessage(msgWithDescription), VALID);
const msgWithSummaryAndDescription =
'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE: This is a summary of a breaking change.\n\n' +
'This is a full description of the breaking change.';
expectValidationResult(validateCommitMessage(msgWithSummaryAndDescription), VALID);
const msgWithNonBreaking = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is not a\n' +
'breaking change commit.';
expectValidationResult(validateCommitMessage(msgWithNonBreaking), VALID);
});
it('should fail for non-valid breaking change commit descriptions', () => {
const msgWithSummary = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE This is a summary of a breaking change.';
expectValidationResult(
validateCommitMessage(msgWithSummary), INVALID,
[`The commit message body contains an invalid breaking change description.`]);
const msgWithPlural = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGES: This is a summary of a breaking change.';
expectValidationResult(
validateCommitMessage(msgWithPlural), INVALID,
[`The commit message body contains an invalid breaking change description.`]);
const msgWithDescription = 'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE:\n' +
'This is a full description of the breaking change.';
expectValidationResult(
validateCommitMessage(msgWithDescription), INVALID,
[`The commit message body contains an invalid breaking change description.`]);
const msgWithSummaryAndDescription =
'feat(compiler): this is just an usual commit message tile\n\n' +
'This is a normal commit message body which does not exceed the max length\n' +
'limit. For more details see the following super long URL:\n\n' +
'BREAKING CHANGE\n\n' +
'This is a full description of the breaking change.';
expectValidationResult(
validateCommitMessage(msgWithSummaryAndDescription), INVALID,
[`The commit message body contains an invalid breaking change description.`]);
});
});
}); });
}); });

View File

@ -25,6 +25,16 @@ export interface ValidateCommitMessageResult {
/** Regex matching a URL for an entire commit body line. */ /** Regex matching a URL for an entire commit body line. */
const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/; const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/;
/**
* Regex matching a breaking change.
*
* - Starts with BREAKING CHANGE
* - Followed by a colon
* - Followed by a single space or two consecutive new lines
*
* NB: Anything after `BREAKING CHANGE` is optional to facilitate the validation.
*/
const COMMIT_BODY_BREAKING_CHANGE_RE = /^BREAKING CHANGE(:( |\n{2}))?/m;
/** Validate a commit message against using the local repo's config. */ /** Validate a commit message against using the local repo's config. */
export function validateCommitMessage( export function validateCommitMessage(
@ -137,11 +147,24 @@ export function validateCommitMessage(
}); });
if (lineExceedsMaxLength) { if (lineExceedsMaxLength) {
errors.push( errors.push(`The commit message body contains lines greater than ${
`The commit message body contains lines greater than ${config.maxLineLength} characters`); config.maxLineLength} characters.`);
return false; return false;
} }
// Breaking change
// Check if the commit message contains a valid break change description.
// https://github.com/angular/angular/blob/88fbc066775ab1a2f6a8c75f933375b46d8fa9a4/CONTRIBUTING.md#commit-message-footer
const hasBreakingChange = COMMIT_BODY_BREAKING_CHANGE_RE.exec(commit.body);
if (hasBreakingChange !== null) {
const [, breakingChangeDescription] = hasBreakingChange;
if (!breakingChangeDescription) {
// Not followed by :, space or two consecutive new lines,
errors.push(`The commit message body contains an invalid breaking change description.`);
return false;
}
}
return true; return true;
} }
@ -160,4 +183,9 @@ export function printValidationErrors(errors: string[], print = error) {
print(); print();
print('<body>'); print('<body>');
print(); print();
print(`BREAKING CHANGE: <breaking change summary>`);
print();
print(`<breaking change description>`);
print();
print();
} }

View File

@ -1817,6 +1817,16 @@ function parseCommitMessagesForRange(range) {
*/ */
/** Regex matching a URL for an entire commit body line. */ /** Regex matching a URL for an entire commit body line. */
const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/; const COMMIT_BODY_URL_LINE_RE = /^https?:\/\/.*$/;
/**
* Regex matching a breaking change.
*
* - Starts with BREAKING CHANGE
* - Followed by a colon
* - Followed by a single space or two consecutive new lines
*
* NB: Anything after `BREAKING CHANGE` is optional to facilitate the validation.
*/
const COMMIT_BODY_BREAKING_CHANGE_RE = /^BREAKING CHANGE(:( |\n{2}))?/m;
/** Validate a commit message against using the local repo's config. */ /** Validate a commit message against using the local repo's config. */
function validateCommitMessage(commitMsg, options = {}) { function validateCommitMessage(commitMsg, options = {}) {
const config = getCommitMessageConfig().commitMessage; const config = getCommitMessageConfig().commitMessage;
@ -1903,9 +1913,21 @@ function validateCommitMessage(commitMsg, options = {}) {
return line.length > config.maxLineLength && !COMMIT_BODY_URL_LINE_RE.test(line); return line.length > config.maxLineLength && !COMMIT_BODY_URL_LINE_RE.test(line);
}); });
if (lineExceedsMaxLength) { if (lineExceedsMaxLength) {
errors.push(`The commit message body contains lines greater than ${config.maxLineLength} characters`); errors.push(`The commit message body contains lines greater than ${config.maxLineLength} characters.`);
return false; return false;
} }
// Breaking change
// Check if the commit message contains a valid break change description.
// https://github.com/angular/angular/blob/88fbc066775ab1a2f6a8c75f933375b46d8fa9a4/CONTRIBUTING.md#commit-message-footer
const hasBreakingChange = COMMIT_BODY_BREAKING_CHANGE_RE.exec(commit.body);
if (hasBreakingChange !== null) {
const [, breakingChangeDescription] = hasBreakingChange;
if (!breakingChangeDescription) {
// Not followed by :, space or two consecutive new lines,
errors.push(`The commit message body contains an invalid breaking change description.`);
return false;
}
}
return true; return true;
} }
return { valid: validateCommitAndCollectErrors(), errors, commit }; return { valid: validateCommitAndCollectErrors(), errors, commit };
@ -1921,6 +1943,11 @@ function printValidationErrors(errors, print = error) {
print(); print();
print('<body>'); print('<body>');
print(); print();
print(`BREAKING CHANGE: <breaking change summary>`);
print();
print(`<breaking change description>`);
print();
print();
} }
/** /**