-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5ce18b7
commit 2e3eb1b
Showing
1 changed file
with
136 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
"""Internal tool to update the changelog.""" | ||
|
||
import subprocess | ||
from dataclasses import dataclass | ||
from datetime import datetime | ||
from typing import List | ||
|
||
|
||
@dataclass(frozen=True) | ||
class Change: | ||
commit_hash: str | ||
prefix: str | ||
message: str | ||
|
||
|
||
def main(changelog_path: str): | ||
changelog = get_changelog(changelog_path) | ||
git_tag = get_most_recent_git_tag() | ||
changes = get_formatted_changes(git_tag) | ||
print("-" * 80) | ||
print(changes) | ||
# TODO: Write changes to changelog | ||
new_version = version_bump(git_tag) | ||
today = datetime.now() | ||
header = f"Version {new_version}, {today:%Y-%m-%d}\n" | ||
header = header + "-" * (len(header) - 1) + "\n" | ||
trailer = f"All changes: https://github.com/py-pdf/PyPDF2/compare/{git_tag}...{new_version}" | ||
new_entry = header + changes + trailer | ||
print(new_entry) | ||
|
||
# TODO: Make idempotent - multiple calls to this script | ||
# should not change the changelog | ||
new_changelog = new_entry + changelog | ||
write_changelog(new_changelog, changelog_path) | ||
|
||
|
||
def version_bump(git_tag: str) -> str: | ||
# just assume a patch version change | ||
major, minor, patch = git_tag.split(".") | ||
return f"{major}.{minor}.{int(patch) + 1}" | ||
|
||
|
||
def get_changelog(changelog_path: str) -> str: | ||
with open(changelog_path, "r") as fh: | ||
changelog = fh.read() | ||
return changelog | ||
|
||
|
||
def write_changelog(new_changelog: str, changelog_path: str) -> None: | ||
with open(changelog_path, "w") as fh: | ||
fh.write(new_changelog) | ||
|
||
|
||
def get_formatted_changes(git_tag: str) -> str: | ||
commits = get_git_commits_since_tag(git_tag) | ||
|
||
# Group by prefix | ||
grouped = {} | ||
for commit in commits: | ||
if commit.prefix not in grouped: | ||
grouped[commit.prefix] = [] | ||
grouped[commit.prefix].append({"msg": commit.message}) | ||
|
||
# Order prefixes | ||
order = ["DEP", "ENH", "BUG", "ROB", "DOC", "DEV", "MAINT", "TST", "STY"] | ||
abbrev2long = { | ||
"DEP": "Deprecations", | ||
"ENH": "New Features", | ||
"BUG": "Bug Fixes", | ||
"ROB": "Robustness", | ||
"DOC": "Documentation", | ||
"DEV": "Developer Experience", | ||
"MAINT": "Maintenance", | ||
"TST": "Testing", | ||
"STY": "Code Style", | ||
} | ||
|
||
# Create output | ||
output = "" | ||
for prefix in order: | ||
if prefix not in grouped: | ||
continue | ||
output += f"\n{abbrev2long[prefix]} ({prefix}):\n" # header | ||
for commit in grouped[prefix]: | ||
output += f"- {commit['msg']}\n" | ||
del grouped[prefix] | ||
|
||
if grouped: | ||
print("@" * 80) | ||
output += "\nYou forgot something!:\n" | ||
for prefix in grouped: | ||
output += f"- {prefix}: {grouped[prefix]}\n" | ||
print("@" * 80) | ||
|
||
return output | ||
|
||
|
||
def get_most_recent_git_tag(): | ||
git_tag = str( | ||
subprocess.check_output( | ||
["git", "describe", "--abbrev=0"], stderr=subprocess.STDOUT | ||
) | ||
).strip("'b\\n") | ||
return git_tag | ||
|
||
|
||
def get_git_commits_since_tag(git_tag) -> List[Change]: | ||
commits = str( | ||
subprocess.check_output( | ||
["git", "--no-pager", "log", f"{git_tag}..HEAD", "--oneline"], | ||
stderr=subprocess.STDOUT, | ||
) | ||
).strip("'b\\n") | ||
return [parse_commit_line(line) for line in commits.split("\\n")] | ||
|
||
|
||
def parse_commit_line(line) -> Change: | ||
commit_hash, rest = line[: len("d5a5eea")], line[len("d5a5eea") :] | ||
if ":" in rest: | ||
prefix, message = rest.split(":", 1) | ||
else: | ||
prefix = "" | ||
message = rest | ||
|
||
# Standardize | ||
message.strip() | ||
|
||
prefix = prefix.strip() | ||
if prefix == "DOCS": | ||
prefix = "DOC" | ||
|
||
return Change(commit_hash=commit_hash, prefix=prefix, message=message) | ||
|
||
|
||
if __name__ == "__main__": | ||
main("CHANGELOG") |