diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6aa4fdba1a..e7979d8fc59 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -52,6 +52,7 @@ repos: alias: check-changelog-entries name: Check Changelog Entries args: + - pre-commit - changelog - pre-commit-checks additional_dependencies: @@ -67,6 +68,7 @@ repos: pass_filenames: false args: - pre-commit + - workflows - generate-workflows additional_dependencies: - boto3==1.21.46 @@ -82,6 +84,7 @@ repos: - yaml args: - pre-commit + - workflows - actionlint additional_dependencies: - boto3==1.21.46 diff --git a/tools/__init__.py b/tools/__init__.py index 01f3e188441..db61bd0ba16 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -10,7 +10,9 @@ ptscripts.register_tools_module("tools.pkg.repo") ptscripts.register_tools_module("tools.pkg.build") ptscripts.register_tools_module("tools.pkg.repo.create") ptscripts.register_tools_module("tools.pkg.repo.publish") -ptscripts.register_tools_module("tools.pre_commit") +ptscripts.register_tools_module("tools.precommit") +ptscripts.register_tools_module("tools.precommit.changelog") +ptscripts.register_tools_module("tools.precommit.workflows") ptscripts.register_tools_module("tools.release") ptscripts.register_tools_module("tools.testsuite") ptscripts.register_tools_module("tools.testsuite.download") diff --git a/tools/changelog.py b/tools/changelog.py index d4d8b662829..12bbba22d3c 100644 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -8,7 +8,6 @@ import datetime import logging import os import pathlib -import re import sys import textwrap @@ -17,19 +16,6 @@ from ptscripts import Context, command_group from tools.utils import REPO_ROOT, Version -CHANGELOG_LIKE_RE = re.compile(r"([\d]+)\.([a-z]+)$") -CHANGELOG_TYPES = ( - "removed", - "deprecated", - "changed", - "fixed", - "added", - "security", -) -CHANGELOG_ENTRY_RE = re.compile( - r"([\d]+|(CVE|cve)-[\d]{{4}}-[\d]+)\.({})(\.md)?$".format("|".join(CHANGELOG_TYPES)) -) - log = logging.getLogger(__name__) # Define the command group @@ -50,103 +36,6 @@ changelog = command_group( ) -@changelog.command( - name="pre-commit-checks", - arguments={ - "files": { - "nargs": "*", - } - }, -) -def check_changelog_entries(ctx: Context, files: list[pathlib.Path]): - """ - Run pre-commit checks on changelog snippets. - """ - docs_path = REPO_ROOT / "doc" - tests_integration_files_path = REPO_ROOT / "tests" / "integration" / "files" - changelog_entries_path = REPO_ROOT / "changelog" - exitcode = 0 - for entry in files: - path = pathlib.Path(entry).resolve() - # Is it under changelog/ - try: - path.relative_to(changelog_entries_path) - if path.name in (".keep", ".template.jinja"): - # This is the file we use so git doesn't delete the changelog/ directory - continue - # Is it named properly - if not CHANGELOG_ENTRY_RE.match(path.name): - ctx.error( - "The changelog entry '{}' should have one of the following extensions: {}.".format( - path.relative_to(REPO_ROOT), - ", ".join(f"{ext}.md" for ext in CHANGELOG_TYPES), - ), - ) - exitcode = 1 - continue - if path.suffix != ".md": - ctx.error( - f"Please rename '{path.relative_to(REPO_ROOT)}' to " - f"'{path.relative_to(REPO_ROOT)}.md'" - ) - exitcode = 1 - continue - except ValueError: - # No, carry on - pass - # Does it look like a changelog entry - if CHANGELOG_LIKE_RE.match(path.name) and not CHANGELOG_ENTRY_RE.match( - path.name - ): - try: - # Is this under doc/ - path.relative_to(docs_path) - # Yes, carry on - continue - except ValueError: - # No, resume the check - pass - try: - # Is this under tests/integration/files - path.relative_to(tests_integration_files_path) - # Yes, carry on - continue - except ValueError: - # No, resume the check - pass - ctx.error( - "The changelog entry '{}' should have one of the following extensions: {}.".format( - path.relative_to(REPO_ROOT), - ", ".join(f"{ext}.md" for ext in CHANGELOG_TYPES), - ) - ) - exitcode = 1 - continue - # Is it a changelog entry - if not CHANGELOG_ENTRY_RE.match(path.name): - # No? Carry on - continue - # Is the changelog entry in the right path? - try: - path.relative_to(changelog_entries_path) - except ValueError: - exitcode = 1 - ctx.error( - "The changelog entry '{}' should be placed under '{}/', not '{}'".format( - path.name, - changelog_entries_path.relative_to(REPO_ROOT), - path.relative_to(REPO_ROOT).parent, - ) - ) - if path.suffix != ".md": - ctx.error( - f"Please rename '{path.relative_to(REPO_ROOT)}' to " - f"'{path.relative_to(REPO_ROOT)}.md'" - ) - exitcode = 1 - ctx.exit(exitcode) - - def _get_changelog_contents(ctx: Context, version: Version): """ Return the full changelog generated by towncrier. diff --git a/tools/precommit/__init__.py b/tools/precommit/__init__.py new file mode 100644 index 00000000000..57d9d1ae62a --- /dev/null +++ b/tools/precommit/__init__.py @@ -0,0 +1,9 @@ +""" +These commands, and sub-commands, are used by pre-commit. +""" +from ptscripts import command_group + +# Define the command group +cgroup = command_group( + name="pre-commit", help="Pre-Commit Related Commands", description=__doc__ +) diff --git a/tools/precommit/changelog.py b/tools/precommit/changelog.py new file mode 100644 index 00000000000..5e108af5f11 --- /dev/null +++ b/tools/precommit/changelog.py @@ -0,0 +1,146 @@ +""" +These commands are used to validate changelog entries +""" +# pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated +from __future__ import annotations + +import logging +import pathlib +import re +import sys + +from ptscripts import Context, command_group + +import tools.utils + +log = logging.getLogger(__name__) + +CHANGELOG_LIKE_RE = re.compile(r"([\d]+)\.([a-z]+)$") +CHANGELOG_TYPES = ( + "removed", + "deprecated", + "changed", + "fixed", + "added", + "security", +) +CHANGELOG_ENTRY_RE = re.compile( + r"([\d]+|(CVE|cve)-[\d]{{4}}-[\d]+)\.({})(\.md)?$".format("|".join(CHANGELOG_TYPES)) +) + +# Define the command group +changelog = command_group( + name="changelog", + help="Changelog tools", + description=__doc__, + venv_config={ + "requirements_files": [ + tools.utils.REPO_ROOT + / "requirements" + / "static" + / "ci" + / "py{}.{}".format(*sys.version_info) + / "changelog.txt" + ], + }, + parent="pre-commit", +) + + +@changelog.command( + name="pre-commit-checks", + arguments={ + "files": { + "nargs": "*", + } + }, +) +def check_changelog_entries(ctx: Context, files: list[pathlib.Path]): + """ + Run pre-commit checks on changelog snippets. + """ + docs_path = tools.utils.REPO_ROOT / "doc" + tests_integration_files_path = ( + tools.utils.REPO_ROOT / "tests" / "integration" / "files" + ) + changelog_entries_path = tools.utils.REPO_ROOT / "changelog" + exitcode = 0 + for entry in files: + path = pathlib.Path(entry).resolve() + # Is it under changelog/ + try: + path.relative_to(changelog_entries_path) + if path.name in (".keep", ".template.jinja"): + # This is the file we use so git doesn't delete the changelog/ directory + continue + # Is it named properly + if not CHANGELOG_ENTRY_RE.match(path.name): + ctx.error( + "The changelog entry '{}' should have one of the following extensions: {}.".format( + path.relative_to(tools.utils.REPO_ROOT), + ", ".join(f"{ext}.md" for ext in CHANGELOG_TYPES), + ), + ) + exitcode = 1 + continue + if path.suffix != ".md": + ctx.error( + f"Please rename '{path.relative_to(tools.utils.REPO_ROOT)}' to " + f"'{path.relative_to(tools.utils.REPO_ROOT)}.md'" + ) + exitcode = 1 + continue + except ValueError: + # No, carry on + pass + # Does it look like a changelog entry + if CHANGELOG_LIKE_RE.match(path.name) and not CHANGELOG_ENTRY_RE.match( + path.name + ): + try: + # Is this under doc/ + path.relative_to(docs_path) + # Yes, carry on + continue + except ValueError: + # No, resume the check + pass + try: + # Is this under tests/integration/files + path.relative_to(tests_integration_files_path) + # Yes, carry on + continue + except ValueError: + # No, resume the check + pass + ctx.error( + "The changelog entry '{}' should have one of the following extensions: {}.".format( + path.relative_to(tools.utils.REPO_ROOT), + ", ".join(f"{ext}.md" for ext in CHANGELOG_TYPES), + ) + ) + exitcode = 1 + continue + # Is it a changelog entry + if not CHANGELOG_ENTRY_RE.match(path.name): + # No? Carry on + continue + # Is the changelog entry in the right path? + try: + path.relative_to(changelog_entries_path) + except ValueError: + exitcode = 1 + ctx.error( + "The changelog entry '{}' should be placed under '{}/', not '{}'".format( + path.name, + changelog_entries_path.relative_to(tools.utils.REPO_ROOT), + path.relative_to(tools.utils.REPO_ROOT).parent, + ) + ) + if path.suffix != ".md": + ctx.error( + f"Please rename '{path.relative_to(tools.utils.REPO_ROOT)}' to " + f"'{path.relative_to(tools.utils.REPO_ROOT)}.md'" + ) + exitcode = 1 + ctx.exit(exitcode) diff --git a/tools/pre_commit.py b/tools/precommit/workflows.py similarity index 98% rename from tools/pre_commit.py rename to tools/precommit/workflows.py index 337c18ea012..855a5e07987 100644 --- a/tools/pre_commit.py +++ b/tools/precommit/workflows.py @@ -1,5 +1,5 @@ """ -These commands are used by pre-commit. +These commands are used for our GitHub Actions workflows. """ # pylint: disable=resource-leakage,broad-except,3rd-party-module-not-gated from __future__ import annotations @@ -19,9 +19,13 @@ log = logging.getLogger(__name__) WORKFLOWS = tools.utils.REPO_ROOT / ".github" / "workflows" TEMPLATES = WORKFLOWS / "templates" + # Define the command group cgroup = command_group( - name="pre-commit", help="Pre-Commit Related Commands", description=__doc__ + name="workflows", + help="Pre-Commit GH Actions Workflows Related Commands", + description=__doc__, + parent="pre-commit", )