generate_changelog/rpmautospec/changelog.py
Nils Philippsen 3b5dc34a5d Move things to rpmautospec Python package
This allows us to reuse code, e.g. to get info out of Koji, for both
calculating release tags and generating the changelog.

Signed-off-by: Nils Philippsen <nils@redhat.com>
2020-02-21 18:24:16 +01:00

124 lines
4 KiB
Python

#!/usr/bin/python3
import collections
import datetime
import logging
import os
import subprocess
import sys
import textwrap
import pygit2
_log = logging.getLogger(__name__)
def register_subcommand(subparsers):
subcmd_name = "generate-changelog"
gen_changelog_parser = subparsers.add_parser(
subcmd_name, help="Generate changelog entries from git commit logs",
)
gen_changelog_parser.add_argument("worktree_path", help="Path to the dist-git worktree")
return subcmd_name
def run_command(command, cwd=None):
""" Run the specified command in a specific working directory if one
is specified.
"""
output = None
try:
output = subprocess.check_output(command, cwd=cwd, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
_log.error("Command `{}` return code: `{}`".format(" ".join(command), e.returncode))
_log.error("stdout:\n-------\n{}".format(e.stdout))
_log.error("stderr:\n-------\n{}".format(e.stderr))
raise Exception("Command failed to run")
return output
def main(args):
""" Main method. """
repopath = args.worktree_path
repo_obj = pygit2.Repository(repopath)
name = os.path.basename(repopath)
branch = repo_obj.lookup_branch(repo_obj.head.shorthand)
commit = branch.peel(pygit2.Commit)
nvr = None
new_nvr = None
changed = False
data = collections.defaultdict(list)
for commit in repo_obj.walk(commit.hex, pygit2.GIT_SORT_TIME):
if len(commit.parents) > 1:
# Ignore merge commits
continue
commit_dt = datetime.datetime.utcfromtimestamp(commit.commit_time)
if commit_dt < (datetime.datetime.utcnow() - datetime.timedelta(days=730)):
# Ignore all commits older than 2 years
break
repo_obj.checkout_tree(
commit, strategy=pygit2.GIT_CHECKOUT_FORCE | pygit2.GIT_CHECKOUT_RECREATE_MISSING,
)
if os.path.exists(os.path.join(repopath, f"{name}.spec")):
try:
output = run_command(
[
"rpm",
"--qf",
"%{name} %{version} %{release}\n",
"--specfile",
f"{name}.spec",
],
cwd=repopath,
)
except Exception:
continue
output = tuple(
output.decode("utf-8").strip().split("\n")[0].rsplit(".", 1)[0].split(" ")
)
nvr = "-".join(output)
if commit.parents:
diff = repo_obj.diff(commit.parents[0], commit)
else:
# First commit in the repo
diff = commit.tree.diff_to_tree(swap=True)
if diff.stats.files_changed:
files_changed = [d.new_file.path for d in diff.deltas]
ignore = True
for filename in files_changed:
if filename.endswith((".spec", ".patch")):
ignore = False
if not ignore:
data[output].append(commit)
else:
print("No more spec file, bailing")
break
for nvr in data:
commits = data[nvr].reverse()
for idx, commit in enumerate(data[nvr]):
last_commit = idx + 1 == len(data[nvr])
commit_dt = datetime.datetime.utcfromtimestamp(commit.commit_time)
wrapper = textwrap.TextWrapper(width=75, subsequent_indent=" ")
message = wrapper.fill(commit.message.split("\n")[0].strip("- "))
if last_commit:
print(
f"* {commit_dt.strftime('%a %b %d %Y')} {commit.author.name} <{commit.author.email}> - {nvr[1]}-{nvr[2]}"
)
else:
print(
f"* {commit_dt.strftime('%a %b %d %Y')} {commit.author.name} <{commit.author.email}>"
)
print("- %s" % message)
print()