Merge branch 'changelog-improvements'

* changelog-improvements:
  Generate changelog in a reverse order
  Add PR number into the changelog
  Use authors of the real patches instead of merge commits
  Cleanup changelog.py
This commit is contained in:
Azat Khuzhin 2023-05-20 18:19:04 +02:00
commit 13ce3045c7

View File

@ -2,7 +2,6 @@
import git import git
import argparse import argparse
import re
def parse_opts(): def parse_opts():
p = argparse.ArgumentParser() p = argparse.ArgumentParser()
@ -11,7 +10,20 @@ def parse_opts():
p.add_argument('--abbrev', default=8, type=int) p.add_argument('--abbrev', default=8, type=int)
# git config pretty.le # git config pretty.le
p.add_argument('--format', default=' o %(s)s (%(h)s %(aN)s)') p.add_argument('--format', default=' o %(s)s (%(h)s %(aN)s)')
p.add_argument('--revision-range') # I did not find a way to search PRs by commits (even though web can do
# this), so instead, you should configure your repository to fetch all PRs,
# like this:
#
# [remote "upstream"]
# url = git@github.com:libevent/libevent
# fetch = +refs/heads/*:refs/remotes/upstream/*
# fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
#
# So that the script could obtain the PR number.
#
# I hope that it will work with rebase & squashes.
p.add_argument('--pull-request-refs', default='upstream/pr/')
p.add_argument('revision_range')
return p.parse_args() return p.parse_args()
def main(): def main():
@ -19,25 +31,51 @@ def main():
repo = git.Repo(opts.git_root) repo = git.Repo(opts.git_root)
squash = not opts.no_squash_merge_childs squash = not opts.no_squash_merge_childs
changelog = []
ignore = [] ignore = []
revision_range = opts.revision_range revision_range = opts.revision_range
if not revision_range: if not revision_range:
revision_range = repo.git.describe('--abbrev=0') + '..' revision_range = repo.git.describe('--abbrev=0') + '..'
refs = repo.references
prs = dict()
for ref in refs:
if not ref.name.startswith(opts.pull_request_refs):
continue
prs[ref.commit] = ref.name[len(opts.pull_request_refs):]
for commit in repo.iter_commits(revision_range): for commit in repo.iter_commits(revision_range):
authors = set({commit.author})
pr = prs.get(commit, None)
if squash: if squash:
if commit.hexsha in ignore: if commit.hexsha in ignore:
continue continue
if len(commit.parents) > 1: if len(commit.parents) > 1:
# reset authors, since we do not want to take any credits to
# the merger
authors.clear()
for c in repo.iter_commits('{}..{}'.format(*commit.parents)): for c in repo.iter_commits('{}..{}'.format(*commit.parents)):
ignore.append(c.hexsha) ignore.append(c.hexsha)
print(opts.format % { authors.add(c.author)
's': commit.summary, pr = prs.get(c, pr)
summary = commit.summary
if pr is not None:
pr = f'#{pr}'
if pr not in summary:
summary += f' ({pr})'
changelog.append(opts.format % {
's': summary,
'h': commit.hexsha[:opts.abbrev], 'h': commit.hexsha[:opts.abbrev],
'aN': str(commit.author), # TODO: use GitHub API to extract github user names
'aN': ', '.join(map(str, authors)),
}) })
# NOTE: You cannot use repo.iter_commits(reverse=True) because this will
# break squashing
changelog.reverse()
for entry in changelog:
print(entry)
if __name__ == "__main__": if __name__ == "__main__":
main() main()