update_change_notes.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #!/usr/bin/env node
  2. import { readFileSync, writeFileSync } from "fs"
  3. import { join, dirname } from "path"
  4. import { fileURLToPath } from "url"
  5. const __filename = fileURLToPath(import.meta.url)
  6. const __dirname = dirname(__filename)
  7. /**
  8. * Update change-notes in plugin.xml based on version from gradle.properties and CHANGELOG.md
  9. */
  10. function updateChangeNotes() {
  11. try {
  12. // Read version from gradle.properties
  13. const gradlePropertiesPath = join(__dirname, "../gradle.properties")
  14. const gradlePropertiesContent = readFileSync(gradlePropertiesPath, "utf8")
  15. const gradleVersionMatch = gradlePropertiesContent.match(/^pluginVersion=(.+)$/m)
  16. if (!gradleVersionMatch) {
  17. throw new Error("pluginVersion not found in gradle.properties")
  18. }
  19. const version = gradleVersionMatch[1].trim()
  20. console.log(`Found plugin version: ${version}`)
  21. // Read CHANGELOG.md
  22. const changelogPath = join(__dirname, "../../../CHANGELOG.md")
  23. const changelogContent = readFileSync(changelogPath, "utf8")
  24. // Find the version section in changelog
  25. const versionPattern = new RegExp(`## \\[v${version.replace(/\./g, "\\.")}\\]([\\s\\S]*?)(?=## \\[v|$)`)
  26. const changelogVersionMatch = changelogContent.match(versionPattern)
  27. if (!changelogVersionMatch) {
  28. throw new Error(`Version ${version} not found in CHANGELOG.md`)
  29. }
  30. const changelogSection = changelogVersionMatch[1].trim()
  31. console.log(`Found changelog section for version ${version}`)
  32. // Convert markdown to HTML format suitable for plugin.xml
  33. const changeNotesHtml = convertMarkdownToHtml(changelogSection, version)
  34. // Read plugin.xml.template
  35. const pluginXmlTemplatePath = join(__dirname, "../src/main/resources/META-INF/plugin.xml.template")
  36. const pluginXmlTemplateContent = readFileSync(pluginXmlTemplatePath, "utf8")
  37. // Replace {{CHANGE_NOTES}} placeholder with generated HTML
  38. const updatedPluginXml = pluginXmlTemplateContent.replace(/\{\{CHANGE_NOTES\}\}/g, changeNotesHtml)
  39. // Write updated plugin.xml
  40. const pluginXmlPath = join(__dirname, "../src/main/resources/META-INF/plugin.xml")
  41. writeFileSync(pluginXmlPath, updatedPluginXml, "utf8")
  42. console.log(`✅ Successfully updated change-notes for version ${version} in plugin.xml`)
  43. } catch (error) {
  44. console.error("❌ Error updating change-notes:", error.message)
  45. process.exit(1)
  46. }
  47. }
  48. /**
  49. * Convert markdown changelog to HTML format suitable for plugin.xml
  50. */
  51. function convertMarkdownToHtml(markdown, version) {
  52. let html = ` <h3>Version ${version}</h3>\n <ul>`
  53. // Split into lines and process
  54. const lines = markdown.split("\n").filter((line) => line.trim())
  55. for (const line of lines) {
  56. const trimmedLine = line.trim()
  57. // Skip empty lines and section headers
  58. if (!trimmedLine || trimmedLine.startsWith("##") || trimmedLine.startsWith("###")) {
  59. continue
  60. }
  61. // Handle main bullet points (features/changes)
  62. if (trimmedLine.startsWith("- ")) {
  63. const content = trimmedLine.substring(2).trim()
  64. const cleanContent = cleanMarkdownContent(content)
  65. if (cleanContent) {
  66. html += `\n <li>${escapeHtml(cleanContent)}</li>`
  67. }
  68. }
  69. // Handle sub-bullet points (patch changes, etc.)
  70. else if (trimmedLine.match(/^\s*-\s/)) {
  71. const content = trimmedLine.replace(/^\s*-\s/, "").trim()
  72. const cleanContent = cleanMarkdownContent(content)
  73. if (cleanContent) {
  74. html += `\n <li>${escapeHtml(cleanContent)}</li>`
  75. }
  76. }
  77. }
  78. html += "\n </ul>"
  79. return html
  80. }
  81. /**
  82. * Clean markdown content by removing links, PR references, and contributor mentions
  83. */
  84. function cleanMarkdownContent(content) {
  85. return (
  86. content
  87. // Remove PR links like [#2012](https://github.com/...)
  88. .replace(/\[#\d+\]\([^)]+\)\s*/g, "")
  89. // Remove commit hash links like [`1fd698a`](https://github.com/...)
  90. .replace(/\[`[^`]+`\]\([^)]+\)\s*/g, "")
  91. // Remove GitHub user links like [@catrielmuller](https://github.com/catrielmuller)
  92. .replace(/\[@[^\]]+\]\([^)]+\)\s*/g, "")
  93. // Remove "Thanks @username!" mentions at the beginning
  94. .replace(/^Thanks\s+@[^!]+!\s*-?\s*/g, "")
  95. // Remove "Thanks @username!" mentions anywhere
  96. .replace(/Thanks\s+@[^!]+!\s*-?\s*/g, "")
  97. // Remove "Thanks @username" mentions (without exclamation)
  98. .replace(/Thanks\s+@[^,)]+[,)]\s*/g, "")
  99. // Remove standalone contributor mentions like "(thanks @username!)"
  100. .replace(/\(thanks\s+@[^)]+\)\s*/g, "")
  101. // Remove leftover "Thanks !" patterns
  102. .replace(/Thanks\s*!\s*-?\s*/g, "")
  103. // Remove leading dashes and spaces
  104. .replace(/^[-\s]+/g, "")
  105. // Clean up multiple spaces
  106. .replace(/\s+/g, " ")
  107. .trim()
  108. )
  109. }
  110. /**
  111. * Escape HTML special characters
  112. */
  113. function escapeHtml(text) {
  114. return text
  115. .replace(/&/g, "&amp;")
  116. .replace(/</g, "&lt;")
  117. .replace(/>/g, "&gt;")
  118. .replace(/"/g, "&quot;")
  119. .replace(/'/g, "&#39;")
  120. }
  121. // Run the update if this script is executed directly
  122. if (import.meta.url === `file://${process.argv[1]}`) {
  123. updateChangeNotes()
  124. }
  125. export default updateChangeNotes