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:
parent
b012a56615
commit
e8cae22d66
|
@ -263,5 +263,72 @@ describe('validate-commit-message.js', () => {
|
|||
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.`]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,6 +25,16 @@ export interface ValidateCommitMessageResult {
|
|||
|
||||
/** Regex matching a URL for an entire commit body line. */
|
||||
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. */
|
||||
export function validateCommitMessage(
|
||||
|
@ -137,11 +147,24 @@ export function validateCommitMessage(
|
|||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -160,4 +183,9 @@ export function printValidationErrors(errors: string[], print = error) {
|
|||
print();
|
||||
print('<body>');
|
||||
print();
|
||||
print(`BREAKING CHANGE: <breaking change summary>`);
|
||||
print();
|
||||
print(`<breaking change description>`);
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
|
|
@ -1817,6 +1817,16 @@ function parseCommitMessagesForRange(range) {
|
|||
*/
|
||||
/** Regex matching a URL for an entire commit body line. */
|
||||
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. */
|
||||
function validateCommitMessage(commitMsg, options = {}) {
|
||||
const config = getCommitMessageConfig().commitMessage;
|
||||
|
@ -1903,9 +1913,21 @@ function validateCommitMessage(commitMsg, options = {}) {
|
|||
return line.length > config.maxLineLength && !COMMIT_BODY_URL_LINE_RE.test(line);
|
||||
});
|
||||
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;
|
||||
}
|
||||
// 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 { valid: validateCommitAndCollectErrors(), errors, commit };
|
||||
|
@ -1921,6 +1943,11 @@ function printValidationErrors(errors, print = error) {
|
|||
print();
|
||||
print('<body>');
|
||||
print();
|
||||
print(`BREAKING CHANGE: <breaking change summary>`);
|
||||
print();
|
||||
print(`<breaking change description>`);
|
||||
print();
|
||||
print();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue