diff --git a/.github/workflows/check-news-item.yml b/.github/workflows/check-news-item.yml
deleted file mode 100644
index 02bb64706..000000000
--- a/.github/workflows/check-news-item.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: Check News Item
-
-on:
- pull_request_target:
- branches:
- - main
-
-permissions:
- pull-requests: write
- contents: read
-
-jobs:
- build:
- runs-on: ubuntu-latest
- name: Check News item
- steps:
-
- # note: the checkout will pull code from the base branch. This step should not pull code from the merge commit
- - uses: actions/checkout@v4
-
- - name: Setup Python
- uses: actions/setup-python@v5
- with:
- python-version: '3.9'
- cache: 'pip'
- cache-dependency-path: 'pyproject.toml'
- - run: pip install PyGithub
- - run: python .github/workflows/check-news.py
- env:
- PR_NUMBER: "${{ github.event.number }}"
- GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
- GITHUB_REPOSITORY: "${{ env.GITHUB_REPOSITORY }}"
diff --git a/.github/workflows/check-news.py b/.github/workflows/check-news.py
deleted file mode 100644
index 93ec66dde..000000000
--- a/.github/workflows/check-news.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""Check if the PR has a news item.
-
-Put a warning comment if it doesn't.
-"""
-import os
-from fnmatch import fnmatch
-
-from github import Github, PullRequest
-
-
-def get_added_files(pr: PullRequest.PullRequest):
- print(pr, pr.number)
- for file in pr.get_files():
- if file.status == "added":
- yield file.filename
-
-
-def check_news_file(pr):
- return any(
- map(lambda file_name: fnmatch(file_name, "news/*.rst"), get_added_files(pr))
- )
-
-
-def get_pr_number():
- number = os.environ["PR_NUMBER"]
- if not number:
- raise Exception(f"Pull request number is not found `PR_NUMBER={number}")
- return int(number)
-
-
-def get_old_comment(pr: PullRequest.PullRequest):
- for comment in pr.get_issue_comments():
- if ("github-actions" in comment.user.login) and (
- "No news item is found" in comment.body
- ):
- return comment
-
-
-def main():
- # using an access token
- gh = Github(os.environ["GITHUB_TOKEN"])
- repo = gh.get_repo(os.environ["GITHUB_REPOSITORY"])
- pr = repo.get_pull(get_pr_number())
- has_news_added = check_news_file(pr)
- old_comment = get_old_comment(pr)
-
- if old_comment:
- print("Found an existing comment from bot")
- if has_news_added:
- print("Delete warning from bot, since news items is added.")
- old_comment.delete()
- elif not has_news_added:
- print("No news item found")
-
- pr.create_issue_comment(
- """\
-**Warning!** No news item is found for this PR.
-If this is an user facing change/feature/fix, please add a news item by copying the format from `news/TEMPLATE.rst`.
-"""
- )
-
-
-if __name__ == "__main__":
- main()
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 961fe2d2f..2165cad6e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -37,3 +37,8 @@ repos:
- id: check-yaml
- id: check-toml
- id: check-added-large-files
+ - repo: https://github.com/compilerla/conventional-pre-commit
+ rev: v3.6.0
+ hooks:
+ - id: conventional-pre-commit
+ stages: [commit-msg]
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 1fdee2507..ced118e67 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -38,25 +38,9 @@ Finally, run the following commands. You should see the effects of your change
Changelog
=========
-Pull requests will often have CHANGELOG entries associated with. However,
-to avoid excessive merge conflicts, please follow the following procedure:
-
-1. Go into the ``news/`` directory,
-2. Copy the ``TEMPLATE.rst`` file to another file in the ``news/`` directory.
- We suggest using the branchname::
-
- @ cp TEMPLATE.rst branch.rst
-
-3. Add your entries as a bullet pointed lists in your ``branch.rst`` file in
- the appropriate category. It is OK to leave the ``None`` entries for later
- use.
-4. Commit your ``branch.rst``.
-
-Feel free to update this file whenever you want! Please don't use someone
-else's file name. All of the files in this ``news/`` directory will be merged
-automatically at release time. The ``None`` entries will be automatically
-filtered out too!
-
+We use conventional commits to generate the changelog.
+Please refer to the `conventional commits specification `_
+for more information.
Style Guide
===========
diff --git a/news/TEMPLATE.rst b/news/TEMPLATE.rst
deleted file mode 100644
index 790d30b19..000000000
--- a/news/TEMPLATE.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-**Added:**
-
-*
-
-**Changed:**
-
-*
-
-**Deprecated:**
-
-*
-
-**Removed:**
-
-*
-
-**Fixed:**
-
-*
-
-**Security:**
-
-*
diff --git a/tests/test_news.py b/tests/test_news.py
deleted file mode 100644
index e4bb2fdb1..000000000
--- a/tests/test_news.py
+++ /dev/null
@@ -1,73 +0,0 @@
-"""Testing that news entries are well formed."""
-
-import os
-import re
-
-import pytest
-
-NEWSDIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "news")
-
-CATEGORIES = frozenset(
- ["Added", "Changed", "Deprecated", "Removed", "Fixed", "Security"]
-)
-
-single_grave_reg = re.compile(r"[^`]`[^`]+`[^`_]")
-
-
-def check_news_file(fname):
- import restructuredtext_lint
-
- name = fname.name
- with open(fname.path) as f:
- content = f.read()
- errors = restructuredtext_lint.lint(content)
-
- if errors:
- err_msgs = os.linesep.join(err.message for err in errors)
- pytest.fail(f"{fname}: Invalid ReST\n{err_msgs}")
-
- form = ""
- for i, l in enumerate(content.splitlines()):
- # determine the form of line
- if l.startswith("**"):
- cat = l[2:].rsplit(":")[0]
- if cat not in CATEGORIES:
- pytest.fail(
- f"{name}:{i + 1}: {cat!r} not a proper category "
- f"must be one of {list(CATEGORIES)}"
- "",
- pytrace=True,
- )
- if l.endswith("None"):
- form += "3"
- else:
- form += "2"
- elif l.startswith("* "):
- form += "4"
- elif l.startswith("* ") or l.startswith("- ") or l.startswith(" "):
- form += "1"
- elif l.strip() == "":
- form += "0"
- else:
- pytest.fail(f"{name}:{i + 1}: invalid rst", pytrace=True)
- # The file should have:
- # empty lines around categories
- # at least one content line in a non null category
- reg = re.compile(r"^(3(0|$)|20(1|4)(1|0|4)*0|204$)+$")
- if not reg.match(form):
- print(form)
- pytest.fail(f"{name}: invalid rst", pytrace=True)
-
-
-@pytest.fixture(params=list(os.scandir(NEWSDIR)))
-def fname(request):
- if request.node.config.option.markexpr != "news":
- pytest.skip("Run news items check explicitly")
- return request.param
-
-
-@pytest.mark.news
-def test_news(fname):
- base, ext = os.path.splitext(fname.path)
- assert "rst" in ext
- check_news_file(fname)