mrDescriptionReleaseNotes.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. const { recordRuleExitStatus } = require("./configParameters.js");
  2. /**
  3. * Check if MR Description contains mandatory section "Release notes"
  4. *
  5. * Extracts the content of the "Release notes" section from the GitLab merge request description.
  6. *
  7. * @dangerjs WARN (if section missing, is empty or wrong markdown format)
  8. */
  9. module.exports = function () {
  10. const ruleName = 'Merge request Release Notes section';
  11. const mrDescription = danger.gitlab.mr.description;
  12. const wiki_link = `${process.env.DANGER_GITLAB_HOST}/espressif/esp-idf/-/wikis/rfc/How-to-write-release-notes-properly`;
  13. const regexSectionReleaseNotes = /## Release notes([\s\S]*?)(?=## |$)/;
  14. const regexValidEntry = /^\s*[-*+]\s+.+/;
  15. const regexNoReleaseNotes = /no release note/i;
  16. const sectionReleaseNotes = mrDescription.match(regexSectionReleaseNotes);
  17. if (!sectionReleaseNotes) {
  18. recordRuleExitStatus(ruleName, "Failed");
  19. return warn(`The \`Release Notes\` section seems to be missing. Please check if the section header in MR description is present and in the correct markdown format ("## Release Notes").\n\nSee [Release Notes Format Rules](${wiki_link}).`);
  20. }
  21. const releaseNotesLines = sectionReleaseNotes[1].replace(/<!--[\s\S]*?-->/g, '')
  22. const lines = releaseNotesLines.split("\n").filter(s => s.trim().length > 0);
  23. let valid_entries_found = 0;
  24. let no_release_notes_found = false;
  25. let violations = [];
  26. lines.forEach((line) => {
  27. if (line.match(regexValidEntry)) {
  28. valid_entries_found++;
  29. const error_msg = check_entry(line);
  30. if (error_msg) {
  31. violations.push(error_msg);
  32. }
  33. } else if (line.match(regexNoReleaseNotes)) {
  34. no_release_notes_found = true;
  35. }
  36. });
  37. let error_output = [];
  38. if (violations.length > 0) {
  39. error_output = [...error_output, 'Invalid release note entries:', violations.join('\n')];
  40. }
  41. if (no_release_notes_found) {
  42. if (valid_entries_found > 0) {
  43. error_output.push('`No release notes` comment shows up when there is valid entry. Remove bullets before comments in release notes section.');
  44. }
  45. } else {
  46. if (!valid_entries_found) {
  47. error_output.push('The `Release Notes` section seems to have no valid entries. Add bullets before valid entries, or add `No release notes` comment to suppress this error if you mean to have no release notes.');
  48. }
  49. }
  50. if (error_output.length > 0) {
  51. // Paragraphs joined by double `\n`s.
  52. error_output = [...error_output, `See [Release Notes Format Guide](${wiki_link}).`].join('\n\n');
  53. recordRuleExitStatus(ruleName, "Failed");
  54. return warn(error_output);
  55. }
  56. // At this point, the rule has passed
  57. recordRuleExitStatus(ruleName, 'Passed');
  58. };
  59. function check_entry(entry) {
  60. const entry_str = `- \`${entry}\``;
  61. const indent = " ";
  62. if (entry.match(/no\s+release\s+note/i)) {
  63. return [entry_str, `${indent}- \`No release notes\` comment shouldn't start with bullet.`].join('\n');
  64. }
  65. // Remove a leading escaping backslash of the special characters, https://www.markdownguide.org/basic-syntax/#characters-you-can-escape
  66. const escapeCharRegex = /\\([\\`*_{}[\]<>()+#-.!|])/g;
  67. entry = entry.replace(escapeCharRegex, '$1');
  68. const regex = /^(\s*)[-*+]\s+\[([^\]]+)\]\s+(.*)$/;
  69. const match = regex.exec(entry);
  70. if (!match) {
  71. return [entry_str, `${indent}- Please specify the [area] to which the change belongs (see guide). If this line is just a comment, remove the bullet.`].join('\n');
  72. }
  73. // area is in match[2]
  74. const description = match[3].trim();
  75. let violations = [];
  76. if (match[1]) {
  77. violations.push(`${indent}- Release note entry should start from the beginning of line. (Nested release note not allowed.)`);
  78. }
  79. if (!/^[A-Z0-9]/.test(description)) {
  80. violations.push(`${indent}- Release note statement should start with a capital letter or digit.`);
  81. }
  82. if (violations.length > 0) {
  83. return [entry_str, ...violations].join('\n');
  84. }
  85. return null;
  86. }