From 4572188d8ecbb8e06eb4afa822edc33be82e63fe Mon Sep 17 00:00:00 2001 From: Matthias Dellweg Date: Tue, 13 Oct 2026 16:57:45 +0200 Subject: [PATCH] Add check to find changelog duckups --- .ci/scripts/pr_labels.py | 2 +- .github/workflows/lint.yml | 4 ++ templates/ci/Makefile.j2 | 3 +- .../scripts/check_changelog_snippets.py.j2 | 46 +++++++++++++++++++ .../github/.github/workflows/lint.yml.j2 | 4 ++ utils.py | 2 +- 6 files changed, 58 insertions(+), 3 deletions(-) create mode 100755 templates/github/.ci/scripts/check_changelog_snippets.py.j2 diff --git a/.ci/scripts/pr_labels.py b/.ci/scripts/pr_labels.py index d4ccc5d9..e36f5884 100755 --- a/.ci/scripts/pr_labels.py +++ b/.ci/scripts/pr_labels.py @@ -10,9 +10,9 @@ import re import sys +import tomllib from pathlib import Path -import tomllib from git import Repo diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 40cafdb7..90d0df29 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -62,6 +62,10 @@ jobs: run: | ruff check + - name: "Check Changelog Snippets" + run: | + uv run .ci/scripts/check_changelog_snippets.py + - name: "Run extra lint checks" run: | [ ! -x .ci/scripts/extra_linting.sh ] || .ci/scripts/extra_linting.sh diff --git a/templates/ci/Makefile.j2 b/templates/ci/Makefile.j2 index ac12c34e..b0e2567e 100644 --- a/templates/ci/Makefile.j2 +++ b/templates/ci/Makefile.j2 @@ -10,7 +10,7 @@ lint: yamllint -s -d '{extends: relaxed, rules: {line-length: disable}}' .github/workflows bump-my-version bump --dry-run --allow-dirty release ruff format --check --diff - ruff check + ruff check --output-format concise {%- if check_manifest %} check-manifest {%- endif %} @@ -20,3 +20,4 @@ lint: {%- if check_stray_pulpcore_imports %} sh .ci/scripts/check_pulpcore_imports.sh {%- endif %} + python .ci/scripts/check_changelog_snippets.py diff --git a/templates/github/.ci/scripts/check_changelog_snippets.py.j2 b/templates/github/.ci/scripts/check_changelog_snippets.py.j2 new file mode 100755 index 00000000..aeb598e4 --- /dev/null +++ b/templates/github/.ci/scripts/check_changelog_snippets.py.j2 @@ -0,0 +1,46 @@ +#!/bin/env python3 +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# ] +# /// +import re +import sys +from pathlib import Path + +import tomllib + +EXCEPTIONS = [ + ".TEMPLATE.md", + ".gitkeep", + ".gitignore", + {%- for plugin in plugins %} + {%- if plugin.app_label == "core" %} + "plugin_api", + {%- else %} + "{{ plugin.name | snake }}", + {%- endif %} + {%- endfor %} +] + + +def snippet_valid(path: Path, changelog_exts: list[str]) -> bool: + return (path.name in EXCEPTIONS) or ( + path.suffix in changelog_exts + and (path.stem.startswith("+") or re.fullmatch(r"\d*", path.stem)) + ) + + +if __name__ == "__main__": + with Path("pyproject.toml").open("rb") as fp: + pyproject_toml = tomllib.load(fp) + try: + changelog_exts = [ + f".{item['directory']}" for item in pyproject_toml["tool"]["towncrier"]["type"] + ] + except KeyError: + changelog_exts = [".feature", ".bugfix", ".doc", ".removal", ".misc"] + matches = Path("CHANGES").rglob("*") + invalid_snippets = ", ".join(f"'{s}'" for s in matches if not snippet_valid(s, changelog_exts)) + if invalid_snippets: + sys.exit(f"LINT: Invalid changelog entries: {invalid_snippets}.") diff --git a/templates/github/.github/workflows/lint.yml.j2 b/templates/github/.github/workflows/lint.yml.j2 index 0f3b40d3..336c0d6c 100644 --- a/templates/github/.github/workflows/lint.yml.j2 +++ b/templates/github/.github/workflows/lint.yml.j2 @@ -39,6 +39,10 @@ jobs: run: | ruff check + - name: "Check Changelog Snippets" + run: | + uv run .ci/scripts/check_changelog_snippets.py + - name: "Run extra lint checks" run: | [ ! -x .ci/scripts/extra_linting.sh ] || .ci/scripts/extra_linting.sh diff --git a/utils.py b/utils.py index 34e55102..8e273142 100644 --- a/utils.py +++ b/utils.py @@ -1,12 +1,12 @@ import re import stat import textwrap +import tomllib from datetime import timedelta from pathlib import Path import requests_cache import tomlkit -import tomllib import yaml from packaging.specifiers import SpecifierSet from packaging.version import Version