generate_release_notes.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import enum
  2. import click
  3. import numpy as np
  4. import pandas as pd
  5. @enum.unique
  6. class Area(enum.Enum):
  7. core = 'core'
  8. tests = 'tests'
  9. build = 'build'
  10. apps = 'apps'
  11. docs = 'docs'
  12. def define_area(msg):
  13. areas = [e.value for e in Area]
  14. for area in areas:
  15. if msg.startswith(f'[{area}] '):
  16. return area
  17. return np.NaN
  18. def delete_prefix(msg):
  19. prefixes = [f'[{e.value}] ' for e in Area]
  20. for prefix in prefixes:
  21. if msg.startswith(prefix):
  22. return msg[len(prefix):]
  23. return msg[:]
  24. def write_into_changelog(df, f):
  25. f.write('\n')
  26. for _, row in df.iterrows():
  27. f.write(f"\n{row['commit']} {row['message']}")
  28. f.write('\n')
  29. @click.command()
  30. @click.argument(
  31. 'git_log',
  32. type=click.Path(exists=True)
  33. )
  34. def main(git_log):
  35. """
  36. Script designed to generate release notes template with main sections,
  37. contributors list, and detailed changelog out of .csv SRT git log file.
  38. """
  39. df = pd.read_csv(git_log, sep = '|', names = ['commit', 'message', 'author', 'email'])
  40. df['area'] = df['message'].apply(define_area)
  41. df['message'] = df['message'].apply(delete_prefix)
  42. # Split commits by areas
  43. core = df[df['area']==Area.core.value]
  44. tests = df[df['area']==Area.tests.value]
  45. build = df[df['area']==Area.build.value]
  46. apps = df[df['area']==Area.apps.value]
  47. docs = df[df['area']==Area.docs.value]
  48. other = df[df['area'].isna()]
  49. # Define individual contributors
  50. contributors = df.groupby(['author', 'email'])
  51. contributors = list(contributors.groups.keys())
  52. with open('release-notes.md', 'w') as f:
  53. f.write('# Release Notes\n')
  54. f.write('\n## API / ABI / Integration Changes\n')
  55. f.write('\n**API/ABI version: 1.x.**\n')
  56. f.write('\n## New Features and Improvements\n')
  57. f.write('\n## Important Bug Fixes\n')
  58. f.write('\n## Build\n')
  59. f.write('\n## Documentation\n')
  60. f.write('\n## Contributors\n')
  61. for name, email in contributors:
  62. f.write(f'\n{name} <{email}>')
  63. f.write('\n')
  64. f.write('\n## Changelog\n')
  65. f.write('\n<details><summary>Click to expand/collapse</summary>')
  66. f.write('\n<p>')
  67. f.write('\n')
  68. if not core.empty:
  69. f.write('\n### Core Functionality')
  70. write_into_changelog(core, f)
  71. if not tests.empty:
  72. f.write('\n### Unit Tests')
  73. write_into_changelog(tests, f)
  74. if not build.empty:
  75. f.write('\n### Build Scripts (CMake, etc.)')
  76. write_into_changelog(build, f)
  77. if not apps.empty:
  78. f.write('\n### Sample Applications')
  79. write_into_changelog(apps, f)
  80. if not docs.empty:
  81. f.write('\n### Documentation')
  82. write_into_changelog(docs, f)
  83. if not other.empty:
  84. f.write('\n### Other')
  85. write_into_changelog(other, f)
  86. f.write('\n</p>')
  87. f.write('\n</details>')
  88. if __name__ == '__main__':
  89. main()