sortChanges.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/python
  2. # Copyright (c) 2014-2019, The Tor Project, Inc.
  3. # See LICENSE for licensing information
  4. """This script sorts a bunch of changes files listed on its command
  5. line into roughly the order in which they should appear in the
  6. changelog.
  7. """
  8. import re
  9. import sys
  10. def fetch(fn):
  11. with open(fn) as f:
  12. s = f.read()
  13. s = "%s\n" % s.rstrip()
  14. return s
  15. CSR='Code simplification and refactoring'
  16. REPLACEMENTS = {
  17. # plurals
  18. 'Minor bugfix' : 'Minor bugfixes',
  19. 'Major bugfix' : 'Major bugfixes',
  20. 'Minor feature' : 'Minor features',
  21. 'Major feature' : 'Major features',
  22. 'Removed feature' : 'Removed features',
  23. 'Code simplification and refactorings' : CSR,
  24. 'Code simplifications and refactoring' : CSR,
  25. 'Code simplifications and refactorings' : CSR,
  26. # wrong words
  27. 'Minor fix' : 'Minor bugfixes',
  28. 'Major fix' : 'Major bugfixes',
  29. 'Minor fixes' : 'Minor bugfixes',
  30. 'Major fixes' : 'Major bugfixes',
  31. 'Minor enhancement' : 'Minor features',
  32. 'Minor enhancements' : 'Minor features',
  33. 'Major enhancement' : 'Major features',
  34. 'Major enhancements' : 'Major features',
  35. }
  36. def score(s,fname=None):
  37. m = re.match(r'^ +o ([^\n]*)\n(.*)', s, re.M|re.S)
  38. if not m:
  39. print >>sys.stderr, "Can't score %r from %s"%(s,fname)
  40. heading = m.group(1)
  41. heading = REPLACEMENTS.get(heading, heading)
  42. lw = m.group(1).lower()
  43. if lw.startswith("major feature"):
  44. score = 0
  45. elif lw.startswith("major bug"):
  46. score = 1
  47. elif lw.startswith("major"):
  48. score = 2
  49. elif lw.startswith("minor feature"):
  50. score = 10
  51. elif lw.startswith("minor bug"):
  52. score = 11
  53. elif lw.startswith("minor"):
  54. score = 12
  55. else:
  56. score = 100
  57. return (score, lw, heading, m.group(2))
  58. def splitChanges(s):
  59. this_entry = []
  60. for line in s.split("\n"):
  61. if line.strip() == "":
  62. continue
  63. if re.match(r" +o ", line):
  64. if len(this_entry) > 2:
  65. yield "".join(this_entry)
  66. curHeader = line
  67. this_entry = [ curHeader, "\n" ]
  68. continue
  69. elif re.match(r" +- ", line):
  70. if len(this_entry) > 2:
  71. yield "".join(this_entry)
  72. this_entry = [ curHeader, "\n" ]
  73. this_entry.append(line)
  74. this_entry.append("\n")
  75. if len(this_entry) > 2:
  76. yield "".join(this_entry)
  77. changes = []
  78. for fn in sys.argv[1:]:
  79. if fn.endswith('~'):
  80. continue
  81. for change in splitChanges(fetch(fn)):
  82. changes.append(score(change,fn))
  83. changes.sort()
  84. last_lw = "this is not a header"
  85. for _, lw, header, rest in changes:
  86. if lw == last_lw:
  87. print rest,
  88. else:
  89. print
  90. print " o",header
  91. print rest,
  92. last_lw = lw