2727import urllib .request
2828from os import path
2929from tempfile import TemporaryDirectory
30- from typing import Any , List , Optional
30+ from typing import Any , List , Match , Optional , Union
3131
3232import attr
3333import click
@@ -233,7 +233,7 @@ def _prepare() -> None:
233233 subprocess .check_output (["poetry" , "version" , new_version ])
234234
235235 # Generate changelogs.
236- generate_and_write_changelog (current_version , new_version )
236+ generate_and_write_changelog (synapse_repo , current_version , new_version )
237237
238238 # Generate debian changelogs
239239 if parsed_new_version .pre is not None :
@@ -814,7 +814,7 @@ class VersionSection:
814814
815815
816816def generate_and_write_changelog (
817- current_version : version .Version , new_version : str
817+ repo : Repo , current_version : version .Version , new_version : str
818818) -> None :
819819 # We do this by getting a draft so that we can edit it before writing to the
820820 # changelog.
@@ -827,6 +827,10 @@ def generate_and_write_changelog(
827827 new_changes = new_changes .replace (
828828 "No significant changes." , f"No significant changes since { current_version } ."
829829 )
830+ new_changes += build_dependabot_changelog (
831+ repo ,
832+ current_version ,
833+ )
830834
831835 # Prepend changes to changelog
832836 with open ("CHANGES.md" , "r+" ) as f :
@@ -841,5 +845,47 @@ def generate_and_write_changelog(
841845 os .remove (filename )
842846
843847
848+ def build_dependabot_changelog (repo : Repo , current_version : version .Version ) -> str :
849+ """Summarise dependabot commits between `current_version` and `release_branch`.
850+
851+ Returns an empty string if there have been no such commits; otherwise outputs a
852+ third-level markdown header followed by an unordered list."""
853+ last_release_commit = repo .tag ("v" + str (current_version )).commit
854+ rev_spec = f"{ last_release_commit .hexsha } .."
855+ commits = list (git .objects .Commit .iter_items (repo , rev_spec ))
856+ messages = []
857+ for commit in reversed (commits ):
858+ if commit .author .name == "dependabot[bot]" :
859+ message : Union [str , bytes ] = commit .message
860+ if isinstance (message , bytes ):
861+ message = message .decode ("utf-8" )
862+ messages .append (message .split ("\n " , maxsplit = 1 )[0 ])
863+
864+ if not messages :
865+ print (f"No dependabot commits in range { rev_spec } " , file = sys .stderr )
866+ return ""
867+
868+ messages .sort ()
869+
870+ def replacer (match : Match [str ]) -> str :
871+ desc = match .group (1 )
872+ number = match .group (2 )
873+ return f"* { desc } . ([\\ #{ number } ](https://github.com/matrix-org/synapse/issues/{ number } ))"
874+
875+ for i , message in enumerate (messages ):
876+ messages [i ] = re .sub (r"(.*) \(#(\d+)\)$" , replacer , message )
877+ messages .insert (0 , "### Updates to locked dependencies\n " )
878+ return "\n " .join (messages )
879+
880+
881+ @cli .command ()
882+ @click .argument ("since" )
883+ def test_dependabot_changelog (since : str ) -> None :
884+ """Test building the dependabot changelog.
885+
886+ Summarises all dependabot commits between the SINCE tag and the current git HEAD."""
887+ print (build_dependabot_changelog (git .Repo ("." ), version .Version (since )))
888+
889+
844890if __name__ == "__main__" :
845891 cli ()
0 commit comments