gen-release-notes.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (C) 2024 Puter Technologies Inc.
  3. *
  4. * This file is part of Puter.
  5. *
  6. * Puter is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import { simpleGit } from 'simple-git';
  20. const REPO_URL = 'https://github.com/HeyPuter/puter';
  21. const params = {
  22. from: 'v2.4.0',
  23. // from: 'v2.4.0',
  24. to: 'v2.4.1',
  25. date: '2024-07-11',
  26. };
  27. const git = simpleGit();
  28. const log = await git.log({ from: params.from });
  29. const commits = log.all;
  30. const CC_REGEX = /^([a-z0-9]+)(\([a-z0-9]+\))?:\s(.*)/;
  31. const parse_conventional_commit = message => {
  32. const parts = CC_REGEX.exec(message);
  33. if ( ! parts ) return null;
  34. let [match, type, scope, summary] = parts;
  35. if ( ! match ) return null;
  36. if ( scope ) scope = scope.slice(1, -1);
  37. return { type, scope, summary };
  38. };
  39. const types = {
  40. feat: {
  41. label: 'Features'
  42. },
  43. i18n: {
  44. label: 'Translations'
  45. },
  46. fix: {
  47. label: 'Bug Fixes'
  48. },
  49. };
  50. const scopes = {
  51. puter: {
  52. label: 'Puter'
  53. },
  54. phoenix: {
  55. label: 'Phoenix Shell'
  56. },
  57. git: {
  58. label: 'Puter Git'
  59. },
  60. backend: {
  61. label: 'Backend'
  62. },
  63. gui: {
  64. label: 'GUI'
  65. },
  66. tools: {
  67. ignore: true,
  68. },
  69. };
  70. const scope_aliases = {
  71. main: 'puter',
  72. ui: 'gui',
  73. parsely: 'phoenix',
  74. };
  75. const retro_prefixes_0 = {
  76. i18n: [
  77. '883601142873f10d69c84874499065a7d29af054',
  78. '17145d0be6a9a1445947cc0c4bec8f16a475144c',
  79. 'e61039faf409b0ad85c7513b0123f3f2e92ebe32',
  80. 'bffa192805216fc17045cd8d629f34784dca7f3f',
  81. 'fe5be7f3cf7f336730137293ba86a637e8d8591d',
  82. '78a0acea6980b6d491da4874edbd98e17c0d9577',
  83. 'a96abb5793528d0dc56d75f95d771e1dcf5960d1',
  84. 'f5a8ee1c6ab950d62c90b6257791f026a508b4e4',
  85. '47ec74f0aa6adb3952e6460909029a4acb0c3039',
  86. '473b6512c697854e3f3badae1eb7b87742954da5',
  87. '8440f566b91c9eb4f01addcb850061e3fbe3afc7',
  88. '92abc9947f811f94f17a5ee5a4b73ee2b210900a',
  89. 'cff488f4f4378ca6c7568a585a665f2a3b87b89c',
  90. ],
  91. fix: [
  92. '535475b3c36a37e3319ed067a24fb671790dcda3',
  93. ],
  94. doc: [
  95. '338004474f078a00608af1d0ebf8a7f9534bad28',
  96. '6c4c73a9e85ff8eb5e7663dcce11f4d1f824032b',
  97. ],
  98. };
  99. const retro_prefixes = {};
  100. for ( const prefix in retro_prefixes_0 ) {
  101. for ( const commit_hash of retro_prefixes_0[prefix] ) {
  102. console.log('PREFIX', commit_hash, prefix);
  103. retro_prefixes[commit_hash] = prefix;
  104. }
  105. }
  106. const data = {};
  107. const ensure_scope = name => {
  108. if ( data[name] ) return;
  109. const o = data[name] = {};
  110. for ( const k in types ) o[k] = [];
  111. };
  112. for ( const commit of commits ) {
  113. if ( retro_prefixes.hasOwnProperty(commit.hash) ) {
  114. commit.message = retro_prefixes[commit.hash] + ': ' +
  115. commit.message;
  116. }
  117. const meta = parse_conventional_commit(commit.message);
  118. if ( ! meta ) continue;
  119. let scope = meta.scope ?? 'puter';
  120. while ( scope in scope_aliases ) {
  121. scope = scope_aliases[scope];
  122. }
  123. if ( ! scopes[scope] ) {
  124. console.log(commit);
  125. throw new Error(`missing scope: ${scope}`);
  126. }
  127. if ( scopes[scope].ignore ) continue;
  128. ensure_scope(scope);
  129. if ( types.hasOwnProperty(meta.type) ) {
  130. data[scope][meta.type].push({ meta, commit });
  131. }
  132. }
  133. let s = '';
  134. s += `## ${params.from} (${params.date})\n\n`;
  135. for ( const scope_name in data ) {
  136. const scope = data[scope_name];
  137. s += `### ${scopes[scope_name].label}\n\n`;
  138. for ( const type_name in types ) {
  139. const type = types[type_name];
  140. const items = scope[type_name];
  141. if ( items.length == 0 ) continue;
  142. s += `\n#### ${type.label}\n\n`;
  143. for ( const { meta, commit } of items ) {
  144. const shorthash = commit.hash.slice(0,7)
  145. s += `- ${meta.summary} ([${shorthash}](${REPO_URL}/commit/${commit.hash}))\n`;
  146. }
  147. }
  148. }
  149. console.log(s);