From 328caf007428aac9f6c28d021e57bf3d6bbf78d3 Mon Sep 17 00:00:00 2001
From: Julian Rother <julian@cccv.de>
Date: Tue, 26 Oct 2021 11:14:42 +0200
Subject: [PATCH] Fixes and improvements for changelog auto-generation

The script generated a broken changelog if the current commit is tagged as
a release. That works now.

Additional improvements:
* Merge commits are ignored
* "^fixup!" commits are ignored
* Commit summaries are line-wrapped
* Authors can be merged by manually supplied name mapping
* The first release also includes a list of commits. They were originally
  excluded because the first release contains so many commits, including
  many unclean ones. But excluding those commits also means excluding the
  attribution, so it is not really an option.
* Authors are ordered by the number of their contributions in a release
  to make occasional contributors more visible.
---
 debian/create_changelog.py | 40 +++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/debian/create_changelog.py b/debian/create_changelog.py
index 4be02a75..b62f211c 100755
--- a/debian/create_changelog.py
+++ b/debian/create_changelog.py
@@ -9,6 +9,15 @@ import git
 
 package_name = 'UNKNOWN'
 
+alias_names = {
+	'julian': 'Julian Rother',
+	'Julian': 'Julian Rother',
+}
+
+ignore_commit_regexes = [
+	'^fixup!',
+]
+
 def print_release(tag=None, commits=tuple(), last_tag=None):
 	release_version = '0.0.0'
 	release_author = git.objects.util.Actor('None', 'undefined@example.com')
@@ -45,21 +54,29 @@ def print_release(tag=None, commits=tuple(), last_tag=None):
 	commit_author_names = {} # author name -> key
 	commit_author_commits = {} # key -> list of commits
 	for commit in commits:
+		if any(filter(lambda pattern: re.match(pattern, commit.summary), ignore_commit_regexes)):
+			continue
+		if len(commit.parents) > 1:
+			continue # Ignore merge commits
+		author_name = alias_names.get(commit.author.name, commit.author.name)
 		key = commit_author_emails.get(commit.author.email)
 		if key is None:
-			key = commit_author_names.get(commit.author.name)
+			key = commit_author_names.get(author_name)
 		if key is None:
 			key = commit.author.email
-			commit_authors.append((key, commit.author))
-			commit_author_emails[commit.author.email] = key
-			commit_author_names[commit.author.name] = key
+			commit_authors.append((key, author_name))
+		commit_author_emails[commit.author.email] = key
+		commit_author_names[author_name] = key
 		commit_author_commits[key] = commit_author_commits.get(key, []) + [commit]
-	for key, author in commit_authors:
-		print(f'  [ {author.name} ]')
+	commit_authors.sort(key=lambda args: len(commit_author_commits[args[0]]))
+	for key, author_name in commit_authors:
+		print(f'  [ {author_name} ]')
 		for commit in commit_author_commits[key]:
-			print(f'  * {commit.summary}')
+			lines = '\n'.join(textwrap.wrap(commit.summary, 90))
+			lines = '  * ' + textwrap.indent(lines, '    ').strip()
+			print(lines)
 		print()
-	print(f' -- {release_author.name} <{release_author.email}>  {email.utils.formatdate(release_date)}')
+	print(f' -- {alias_names.get(release_author.name, release_author.name)} <{release_author.email}>  {email.utils.formatdate(release_date)}')
 
 if __name__ == '__main__':
 	repo = git.Repo('.')
@@ -80,9 +97,10 @@ if __name__ == '__main__':
 	for commit in repo.iter_commits('HEAD'):
 		if commit.hexsha in version_commits:
 			prev_tag = version_commits[commit.hexsha]
-			print_release(tag, commits, last_tag=prev_tag)
-			print()
+			if commits:
+				print_release(tag, commits, last_tag=prev_tag)
+				print()
 			tag = prev_tag
 			commits = []
 		commits.append(commit)
-	print_release(tag, [])
+	print_release(tag, commits)
-- 
GitLab