Skip to content

Commit

Permalink
changelog checks
Browse files Browse the repository at this point in the history
path

logs

logs

logs

logs

logs

logs

logs

logs

fixed cmd

fixed cmd

fixed cmd

fixed cmd

fixed cmd

fixed cmd

parse entry

git cmd

parser

parser

parser

parser

parser

restructured

restructured

restructured

restructured

test

Lint

tests

remove binder test

remove print

fix test
  • Loading branch information
neelasha23 committed Feb 13, 2024
1 parent 3ce3149 commit 8c318cc
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 0.7.5dev
* [Feature] Added `--version` option to `pkgmt setup` to specify Python version
* [Feature] Better checks for new entries added to CHANGELOG.md

## 0.7.4 (2023-09-08)

Expand Down
4 changes: 4 additions & 0 deletions src/pkgmt/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ def __init__(self, text, project_root=".") -> None:
def from_path(cls, path, project_root="."):
return cls(text=Path(path).read_text(), project_root=project_root)

def extract_text_from_entry(self):
"""Extract text from a single Changelog entry"""
return _extract_text_from_items(self.tree[0])

def sort_last_section(self):
"""Sorts last section depending on the prefix"""
self.check_latest_changelog_entries()
Expand Down
100 changes: 100 additions & 0 deletions src/pkgmt/fail_if_invalid_changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import subprocess
import argparse
import sys
from pathlib import Path

from pkgmt import changelog


def latest_changelog_header(base_branch):
changelog_contents = (
subprocess.check_output(f"git show {base_branch}:CHANGELOG.md", shell=True)
.decode("utf-8")
.split()
)
for line in changelog_contents:
if "dev" in line:
return line.strip()


def check_modified(base_branch, debug=False):
latest_section_main = latest_changelog_header(base_branch)
text = Path("CHANGELOG.md").read_text()
changelog_parser = changelog.CHANGELOG(text)
latest_section_current = changelog_parser.get_first_subheading()[1].strip()
if latest_section_main != latest_section_current:
print(
f"Latest section in CHANGELOG.md "
f"not up-to-date. Latest section in "
f"{base_branch}: {latest_section_main}"
)
return 1
cmd = (
f"git diff -U0 {base_branch}... -- CHANGELOG.md "
f"| grep '^[+-]' | grep -Ev '^(--- a/|\+\+\+ b/)'" # noqa
)
try:
out = subprocess.check_output(cmd, shell=True).decode("utf-8")
all_diff = [line.strip() for line in out.split("\n")]
git_removals = [
line[1:].strip()
for line in all_diff
if line.startswith("-")
if line[1:].strip() != ""
]
git_additions = [
line[1:].strip()
for line in all_diff
if line.startswith("+")
if line[1:].strip() != ""
]

if len(git_additions) == 0 or out == "" and debug:
print(f"CHANGELOG.md has not been modified with respect to '{base_branch}'")
return 1

if git_removals:
print(
f"These entries have been removed: "
f"{'; '.join(git_removals)}. Please revert the changes."
)
return 1

if git_additions:
latest_entries = changelog_parser.get_latest_changelog_section()
for line in git_additions:
if line:
try:
extracted_text = changelog.CHANGELOG(
line
).extract_text_from_entry()
except KeyError:
continue
if extracted_text[0] not in latest_entries:
print(
f"Entry '{line}' should be added "
f"to section {latest_section_main}"
)
return 1

elif extracted_text[0].strip() == "":
print(f"You have added an empty entry: {line}")
return 1

except subprocess.CalledProcessError:
pass
return 0


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Check if proper modifications has been done to CHANGELOG.md"
)
parser.add_argument(
"-b", "--base-branch", default="main", help="Base branch to compare against"
)
parser.add_argument("--debug", action="store_true", help="Print debug info")

args = parser.parse_args()
return_code = check_modified(args.base_branch, debug=args.debug)
sys.exit(return_code)
24 changes: 24 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,27 @@ def tmp_package_modi_2(root, tmp_empty):
yield tmp_empty

os.chdir(old)


@pytest.fixture
def tmp_package_changelog(root, tmp_empty):
old = Path.cwd()
path_to_templates = root / "tests" / "assets" / "package_name"
shutil.copytree(str(path_to_templates), "copy")
os.chdir("copy")

subprocess.run(["git", "init"])
subprocess.check_call(["git", "config", "commit.gpgsign", "false"])
subprocess.check_call(["git", "config", "user.email", "ci@ploomberio"])
subprocess.check_call(["git", "config", "user.name", "Ploomber"])
subprocess.run(["git", "checkout", "-b", "main"])
with open("CHANGELOG.md", "a") as f:
f.write("\n")
subprocess.run(["git", "add", "--all"])
subprocess.run(["git", "commit", "-m", "init-commit-message"])

subprocess.run(["git", "checkout", "-b", "test_modified_changelog"])

yield tmp_empty

os.chdir(old)
6 changes: 0 additions & 6 deletions tests/test_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,6 @@ def test_check_if_broken(url, code, broken):
assert response.broken == broken


def test_check_if_broken_doesnt_accept_head_request():
response = links.LinkChecker().check_if_broken("https://binder.ploomber.io")
assert response.code == 405
assert not response.broken


@pytest.mark.parametrize(
"extensions, expected",
[
Expand Down
111 changes: 110 additions & 1 deletion tests/test_modified.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest
from pkgmt import fail_if_modified, fail_if_not_modified
import subprocess

from pkgmt import fail_if_modified, fail_if_not_modified, fail_if_invalid_changelog
from pathlib import Path


Expand Down Expand Up @@ -81,3 +83,110 @@ def test_check_modified_in_2(tmp_package_modi_2, base_branch, include_path, retu
fail_if_not_modified.check_modified(base_branch, include_path, debug=True)
== returncode
)


# @pytest.mark.parametrize("contents", ["""
# # CHANGELOG
#
# ## 0.1dev
#
# * [Fix] Fixes #1
# * [Feature] Added feature 1
# """
# ])
def test_check_modified_changelog(tmp_package_changelog):
Path("CHANGELOG.md").write_text(
"""
# CHANGELOG
## 0.1dev
* [Fix] Fixes #1
* [Feature] Added feature 1
"""
)
subprocess.run(["git", "add", "CHANGELOG.md"])
subprocess.run(["git", "commit", "-m", "changelog_modified"])
assert (
fail_if_invalid_changelog.check_modified("main", ["CHANGELOG.md"], debug=True)
== 0
)


@pytest.mark.parametrize(
"contents, message",
[
(
"""
# CHANGELOG
## 0.1dev
* [Fix] Fixes #1
""",
"CHANGELOG.md has not been modified with respect to 'main'",
),
(
"""
# CHANGELOG
## 0.1dev
* [Fix] Fixes #1
""",
"CHANGELOG.md has not been modified with respect to 'main'",
),
(
"""
# CHANGELOG
## 0.0.1dev
* [Fix] Fixes #1
""",
"Latest section in CHANGELOG.md not up-to-date. "
"Latest section in main: 0.1dev",
),
(
"""
# CHANGELOG
## 0.1dev
* [Fix] Fixes #1
## 0.0.1
* [Feature] Some feature
""",
"Entry '* [Feature] Some feature' should be added to section 0.1dev",
),
(
"""
# CHANGELOG
## 0.1dev
* [Fix] Fixes #2
""",
"These entries have been removed: * [Fix] Fixes #1. "
"Please revert the changes.",
),
],
ids=["blanks", "no-change", "outdated-header", "incorrect-section", "removal"],
)
def test_check_modified_changelog_error(
tmp_package_changelog, contents, message, capsys
):
Path("CHANGELOG.md").write_text(contents)
subprocess.run(["git", "add", "CHANGELOG.md"])
subprocess.run(["git", "commit", "-m", "changelog_modified"])
assert fail_if_invalid_changelog.check_modified("main", debug=True) == 1
out = capsys.readouterr().out
assert message in out

0 comments on commit 8c318cc

Please sign in to comment.