Skip to content

Commit

Permalink
[FEAT-#257] Auto-generate Changelog entries.
Browse files Browse the repository at this point in the history
Automatically generate/update `CHANGES.rst` on <RELEASE> commits to `master`.
  • Loading branch information
Nils Diefenbach authored Aug 22, 2019
2 parents 153a5b9 + 8de75cc commit 1049922
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 57 deletions.
5 changes: 0 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,6 @@ jobs:
command: |
python3 ${CI_SCRIPTS_DIR}/bump-part.py
- run:
name: Update Changelog entries
command: |
python3 ${CI_SCRIPTS_DIR}/update-changelog.py
# Publish a wheel and tarball of the Scenario Player to pypi.
deploy-to-pypi:
executor: default-executor
Expand Down
7 changes: 7 additions & 0 deletions .circleci/scripts/bump-part.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
REPO_NAME,
REPO_OWNER,
)
from chlogger import make_chlog

from scenario_player import __version__

Expand Down Expand Up @@ -65,6 +66,7 @@ def get_last_tag():
part = "minor"
break


print(f"Bumping part {part}..")


Expand All @@ -85,6 +87,11 @@ def get_last_tag():
stdout=subprocess.PIPE,
)

if CURRENT_BRANCH == "master" and COMMIT_TYPE == "RELEASE":
r = subprocess.run(f"git --git-dir={PROJECT_GIT_DIR} describe --abbrev=0 --tags", check=True)
tag = r.stdout.decode("UTF-8").strip(" ").strip("\n")
make_chlog(Path(f"{PROJECT_ROOT}/CHANGES.rst"), new_version=tag)

print("Push Bump commit..")
subprocess.run(
f"git --git-dir={PROJECT_GIT_DIR} push --set-upstream origin {CURRENT_BRANCH}".split(" "),
Expand Down
137 changes: 137 additions & 0 deletions .circleci/scripts/chlogger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import pathlib
import re
import subprocess

from typing import List, Tuple
from constants import PROJECT_GIT_DIR, CURRENT_BRANCH, COMMIT_PATTERN, COMMIT_TYPE


def read_git_commit_history_since_tag(
tag
) -> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], List[Tuple[str, str]]]:
"""Return a list of all git commit titles since the given `tag`.
If `tag` is not given, we'll use the previous tag and compare the log up
up to the current tag.
The commits are returned as three lists:
1. feature commits
2. bugfix commits
3. hotfix commits
"""
completed_process = subprocess.run(
f"git --git-dir={PROJECT_GIT_DIR} log {tag}..master --format=%s".split(" "),
check=True,
stdout=subprocess.PIPE,
)
titles = completed_process.stdout.decode("UTF-8").split("\n")

# The body of a commit may include newline characters, so we need to specify
# a custom separator to indicate the end of the commit body.
separator = "<><><>"
completed_process = subprocess.run(
f"git --git-dir={PROJECT_GIT_DIR} log {tag}..master --format=%b{separator}".split(" "),
check=True,
stdout=subprocess.PIPE,
)
bodies = completed_process.stdout.decode("UTF-8").split(separator)

assert len(titles) == len(bodies)

pattern = re.compile(COMMIT_PATTERN)

feats, fixes, hotfixes = [], [], []

for title, body in zip(titles, bodies):
match = pattern.match(title)
if not match:
continue

commit_type = match.groupdict()["TYPE"]

if commit_type == "FEAT":
feats.append((title, body))
elif commit_type == "FIX":
fixes.append((title, body))
elif commit_type == "HOTFIX":
hotfixes.append((title, body))
else:
print(f"No type found, skipping commit '{title}'..")

return feats, fixes, hotfixes


def format_commits(commits: List[Tuple[str, str]]) -> List[str]:
"""Format the given commits for writing to the Changelog.
The expected input Tuple[str, str] format is:
([(FEAT|FIX|HOTFIX)-#123] <Subject>, <Optional body with further details on the commit.>)
The output format is as follows::
r'- #123 <Subject>\n <Optional body with further details on the commit.>\n'
Newlines in the body are honored, and each line indented by 4 spaces automatically.
TODO: Duplicate Issues should share a single Changelog Entry.
"""
if not commits:
return []
pattern = re.compile(COMMIT_PATTERN)
formatted = set()
for title, body in commits:
match = pattern.match(title)
issue, subject = match.groupdict()["ISSUE"], match.groupdict()["SUBJECT"]

entry = f"- {issue} {subject}\n"

if body:
# Make sure the body is indented by 8 spaces.
formatted_body = " ".join(body.split("\n"))
entry += f"{formatted_body}\n"
formatted.add(entry)
return sorted(formatted)


def update_chlog(
tag: str,
feats: List[str],
fixes: List[str],
hotfixes: List[str],
chlog_path: pathlib.Path = pathlib.Path("CHANGELOG.rst"),
):
try:
history = chlog_path.read_text()
except FileNotFoundError:
print("No Changelog file found - creating a new one.")
history = ""

chlog_entry = f"RELEASE {tag}\n=============\n\n"

if feats:
feats = "\n".join(feats)
chlog_entry += f"Features\n--------\n{feats}\n"""

if fixes:
fixes = "\n".join(fixes)

chlog_entry += f"Fixes\n-----\n{fixes}\n"

if hotfixes:
hotfixes = "\n".join(hotfixes)

chlog_entry += f"Hotfixes\n--------\n{hotfixes}\n"
chlog_path.write_text(f"{chlog_entry}\n{history}")


def make_chlog(chlog_path, new_version):
feats, fixes, hotfixes = read_git_commit_history_since_tag(new_version)
update_chlog(
"0.4.0", format_commits(feats), format_commits(fixes), format_commits(hotfixes), chlog_path
)

subprocess.run(f"git --git-dir={PROJECT_GIT_DIR} git add CHANGELOG.rst".split(" "), check=True)
subprocess.run(
f"git --git-dir={PROJECT_GIT_DIR} git commit CHANGELOG.rst -m \"Update Changelog.\"".split(" "),
check=True
)
2 changes: 1 addition & 1 deletion .circleci/scripts/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
PROJECT_ROOT = os.environ["PROJECT_ROOT"]
COMMIT_SHA = os.environ["CIRCLE_SHA1"]

COMMIT_PATTERN = r"^\[(?P<TYPE>(FEAT|FIX|HOTFIX))-(?P<ISSUE>#\d+)\]\w?(?P<SUBJECT>)"
COMMIT_PATTERN = r"^\[(?P<TYPE>(FEAT|FIX|HOTFIX))-(?P<ISSUE>#\d+)\]\w?(?P<SUBJECT>.*$)"
RELEASE_COMMIT_PATTERN = r"^\[(?P<TYPE>RELEASE)\]\w?(?P<SUBJECT>)"
BUMPVERSION_PREFIX = "Cut New Release:"
CURRENT_BRANCH = os.environ.get("CIRCLE_BRANCH")
Expand Down
51 changes: 0 additions & 51 deletions .circleci/scripts/update-changelog.py

This file was deleted.

0 comments on commit 1049922

Please sign in to comment.