diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 7c10e6a8fc..6a7f9c4ca9 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -9,6 +9,10 @@ FRR Release Procedure Stage 1 - Preparation --------------------- +#. Prepare changelog for the new release + + Note: use ``tools/release_notes.py`` to help draft release notes changelog + #. Checkout the existing ``dev/`` branch. .. code-block:: console diff --git a/tools/release_notes.py b/tools/release_notes.py new file mode 100755 index 0000000000..7481cc18c3 --- /dev/null +++ b/tools/release_notes.py @@ -0,0 +1,93 @@ +#!/usr/bin/python3 +# +# 2021 Jafar Al-Gharaibeh, ATCorp +# +# Generate a draft FRR release notes +# + +import sys +import os +import getopt +import subprocess + +def run(cmd): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rv = proc.communicate("")[0].decode("UTF-8") + proc.wait() + return rv + + +def usage(n): + print(os.path.basename(__file__), " [-b ] [-t ]") + print(" Generate one line logs for non merge commits") + print(" -branch: branch name to use, default to HEAD") + print(" -tag : generate logs up to this tag, default to latest tag") + sys.exit(n) + + +def main(argv): + branch = tag = None + try: + opts, args = getopt.getopt(argv, "hb:t:", ["branch=", "tag="]) + except getopt.GetoptError: + usage(2) + for opt, arg in opts: + if opt == "-h": + usage(0) + elif opt in ("-b", "--branch"): + branch = arg + elif opt in ("-t", "--tag"): + tag = arg + + if branch is None: + branch = "HEAD" + if tag is None: + tag = run(["git", "describe", "--abbrev=0"]).strip("\n") + + chnglog = run( + ["git", "log", "--no-merges", "--pretty=format:'%s%d'", tag + ".." + branch] + ) + chnglog = chnglog.split("\n") + + chnglist = [] + daemons = [ + "babel", + "bgp", + "eigrp", + "nhrp", + "ospf", + "ospf6", + "pbr", + "pim", + "rip", + "ripng", + "sharp", + "vrrp", + "zebra", + ] + + for line in chnglog: + line = line.strip("'") + colon = line.partition(":") + label = colon[0].strip().lower() + if label in daemons: + label = label + "d" + comment = colon[2].strip().capitalize() + chnglist.append(label + ":" + comment) + + chnglist.sort() + lastlabel = "" + for line in chnglist: + colon = line.partition(":") + label = colon[0] + comment = colon[2] + if label != lastlabel: + print("") + print(label) + lastlabel = label + + print(" ", comment) + + +if __name__ == "__main__": + main(sys.argv[1:])