Skip to content

Commit 96997aa

Browse files
chore: Dropped support for Python 3.8 and use Ruff to lint (#98)
1 parent 1726891 commit 96997aa

File tree

8 files changed

+361
-279
lines changed

8 files changed

+361
-279
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ on:
44
push:
55
branches: [ main ]
66
pull_request:
7+
workflow_dispatch:
78

89
jobs:
910
pytest:
@@ -12,7 +13,6 @@ jobs:
1213
strategy:
1314
matrix:
1415
python-version:
15-
- "3.8"
1616
- "3.9"
1717
- "3.10"
1818
- "3.11"

.pre-commit-config.yaml

+5-14
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,9 @@ repos:
1212
- id: end-of-file-fixer
1313
- id: trailing-whitespace
1414

15-
- repo: https://github.com/psf/black
16-
rev: 24.10.0
15+
- repo: https://github.com/astral-sh/ruff-pre-commit
16+
rev: v0.7.4
1717
hooks:
18-
- id: black
19-
20-
- repo: https://github.com/pycqa/isort
21-
rev: 5.13.2
22-
hooks:
23-
- id: isort
24-
25-
- repo: https://github.com/asottile/pyupgrade
26-
rev: v3.19.0
27-
hooks:
28-
- id: pyupgrade
29-
args: [--py38-plus]
18+
- id: ruff
19+
args: [ --fix ]
20+
- id: ruff-format

cz_version_bump/__init__.py

+28-23
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
import re
5+
import typing as t
56
from collections import OrderedDict
67
from textwrap import dedent
78

@@ -12,19 +13,19 @@
1213

1314
from commitizen import defaults, git
1415
from commitizen.cz.base import BaseCommitizen
15-
from commitizen.defaults import Questions
1616

1717
from cz_version_bump.git import repo_name_from_git_remote
1818
from cz_version_bump.thanks import Thanker
1919

20+
if t.TYPE_CHECKING:
21+
from commitizen.defaults import Questions
22+
2023
issue_id_pattern = re.compile(r"\s+\(#(\d+)\)$")
2124

2225

2326
class MeltanoCommitizen(BaseCommitizen):
24-
bump_pattern = defaults.bump_pattern
25-
bump_map = defaults.bump_map
26-
bump_pattern = r"^(feat|fix|refactor|perf|break|docs|ci|chore|style|revert|test|build|packaging)(\(.+\))?(!)?"
27-
bump_map = OrderedDict(
27+
bump_pattern = r"^(feat|fix|refactor|perf|break|docs|ci|chore|style|revert|test|build|packaging)(\(.+\))?(!)?" # noqa: E501
28+
bump_map: t.ClassVar = OrderedDict(
2829
(
2930
(
3031
r"^break",
@@ -44,8 +45,8 @@ class MeltanoCommitizen(BaseCommitizen):
4445
(r"^packaging", defaults.PATCH),
4546
)
4647
)
47-
commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|break|docs|packaging)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?"
48-
schema_pattern = r"(feat|fix|refactor|perf|break|docs|ci|chore|style|revert|test|build|packaging)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:(\s.*)"
48+
commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|break|docs|packaging)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?" # noqa: E501
49+
schema_pattern = r"(feat|fix|refactor|perf|break|docs|ci|chore|style|revert|test|build|packaging)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:(\s.*)" # noqa: E501
4950
schema = dedent(
5051
"""
5152
<type>(<scope>): <subject>
@@ -55,7 +56,7 @@ class MeltanoCommitizen(BaseCommitizen):
5556
(BREAKING CHANGE: )<footer>
5657
"""
5758
).strip("\n")
58-
change_type_order = [
59+
change_type_order = [ # noqa: RUF012
5960
"BREAKING CHANGES",
6061
"✨ New",
6162
"🐛 Fixes",
@@ -64,7 +65,7 @@ class MeltanoCommitizen(BaseCommitizen):
6465
"📚 Documentation Improvements",
6566
"📦 Packaging changes",
6667
]
67-
change_type_map = {
68+
change_type_map = { # noqa: RUF012
6869
"break": "BREAKING CHANGES",
6970
"feat": "✨ New",
7071
"fix": "🐛 Fixes",
@@ -74,14 +75,14 @@ class MeltanoCommitizen(BaseCommitizen):
7475
"packaging": "📦 Packaging changes",
7576
}
7677

77-
def __init__(self, *args, **kwargs):
78+
def __init__(self: MeltanoCommitizen, *args: t.Any, **kwargs: t.Any) -> None:
7879
super().__init__(*args, **kwargs)
7980
self.repo_name = os.environ.get(
8081
"GITHUB_REPOSITORY", repo_name_from_git_remote()
8182
)
8283
self.thanker = Thanker(self.repo_name)
8384

84-
def questions(self) -> Questions:
85+
def questions(self: MeltanoCommitizen) -> Questions:
8586
"""Questions regarding the commit message."""
8687
return [
8788
{
@@ -92,7 +93,7 @@ def questions(self) -> Questions:
9293
{"value": "fix", "name": "fix: A bug fix."},
9394
{
9495
"value": "refactor",
95-
"name": "refactor: A code change that neither fixes a bug nor adds a feature.",
96+
"name": "refactor: A code change that neither fixes a bug nor adds a feature.", # noqa: E501
9697
},
9798
{
9899
"value": "perf",
@@ -102,7 +103,7 @@ def questions(self) -> Questions:
102103
{"value": "break", "name": "break: A breaking change."},
103104
{
104105
"value": "chore",
105-
"name": "chore: A change that doesn't affect the meaning of the codebase.",
106+
"name": "chore: A change that doesn't affect the meaning of the codebase.", # noqa: E501
106107
},
107108
{"value": "style", "name": "style: A code style change."},
108109
{"value": "revert", "name": "revert: Revert to a commit."},
@@ -111,7 +112,7 @@ def questions(self) -> Questions:
111112
{"value": "ci", "name": "ci: A change to CI/CD."},
112113
{
113114
"value": "packaging",
114-
"name": "packaging: A change to how the project is packaged or distributed.",
115+
"name": "packaging: A change to how the project is packaged or distributed.", # noqa: E501
115116
},
116117
],
117118
"message": "Select the type of change you are committing",
@@ -123,15 +124,15 @@ def questions(self) -> Questions:
123124
},
124125
]
125126

126-
def message(self, answers: dict) -> str:
127+
def message(self: MeltanoCommitizen, answers: dict) -> str:
127128
"""Format the git message."""
128129
message_template = Template("{{change_type}}: {{message}}")
129130
if getattr(Template, "substitute", None):
130131
return message_template.substitute(**answers)
131132
return message_template.render(**answers)
132133

133134
def changelog_message_builder_hook(
134-
self,
135+
self: MeltanoCommitizen,
135136
parsed_message: dict[str, str],
136137
commit: git.GitCommit,
137138
) -> dict:
@@ -154,13 +155,13 @@ def changelog_message_builder_hook(
154155
# Convert to int then back to str to validate that it is an integer:
155156
issue_id = str(int(issue_id_pattern.findall(message)[0]))
156157
message = issue_id_pattern.sub("", message)
157-
except Exception:
158+
except Exception: # noqa: BLE001, S110
158159
pass
159160
else:
160-
# NOTE: The "issue ID" will usually be for a pull request. GitHub considers PRs to be
161-
# issues in their APIs, but not vice versa.
161+
# NOTE: The "issue ID" will usually be for a pull request. GitHub considers
162+
# PRs to be issues in their APIs, but not vice versa.
162163
parsed_message["message"] = (
163-
f"[#{issue_id}](https://github.com/{self.repo_name}/issues/{issue_id}) {message}"
164+
f"[#{issue_id}](https://github.com/{self.repo_name}/issues/{issue_id}) {message}" # noqa: E501
164165
)
165166

166167
# Remove the scope because we are too inconsistent with them.
@@ -169,13 +170,17 @@ def changelog_message_builder_hook(
169170
# Thank third-party contributors:
170171
parsed_message["message"] += self.thanker.thanks_message(commit)
171172

172-
# Remove the commit message body because is isn't needed for the changelog, and can cause
173-
# formatting issues if present.
173+
# Remove the commit message body because is isn't needed for the changelog, and
174+
# can cause formatting issues if present.
174175
commit.body = ""
175176

176177
return parsed_message
177178

178-
def changelog_hook(self, full_changelog: str, partial_changelog: str | None) -> str:
179+
def changelog_hook(
180+
self: MeltanoCommitizen,
181+
full_changelog: str,
182+
partial_changelog: str | None,
183+
) -> str:
179184
"""Perform custom action at the end of changelog generation.
180185
181186
full_changelog: The full changelog about to being written into the file.

cz_version_bump/git.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33

44
def repo_name_from_git_remote() -> str:
5-
git_remote_output = subprocess.run(
5+
git_remote_output = subprocess.run( # noqa: S603
66
("git", "remote", "-v"),
77
stdout=subprocess.PIPE,
88
text=True,
9+
check=False,
910
).stdout
1011
github_remote = next(x for x in git_remote_output.split() if "github.com" in x)
1112

cz_version_bump/thanks.py

+29-16
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,43 @@
44

55
import os
66
import re
7-
from typing import Iterable
7+
import typing as t
88
from warnings import warn
99

10-
from commitizen import git
1110
from github import Auth, Consts, Github
1211

12+
if t.TYPE_CHECKING:
13+
from collections.abc import Iterable
14+
15+
from commitizen import git
16+
1317

1418
class Thanker:
1519
co_author_pattern = re.compile(r"<(.*)>$")
1620

17-
def __init__(self, repo_name: str, base_url: str = Consts.DEFAULT_BASE_URL) -> None:
21+
def __init__(
22+
self: Thanker,
23+
repo_name: str,
24+
base_url: str = Consts.DEFAULT_BASE_URL,
25+
) -> None:
1826
github_token = os.environ.get(
1927
"INPUT_GITHUB_TOKEN", os.environ.get("GITHUB_TOKEN", None)
2028
)
2129
if github_token is None:
2230
warn(
2331
"No GitHub token provided - changelog may include "
24-
"thanks for first-party contributors"
32+
"thanks for first-party contributors",
33+
stacklevel=2,
2534
)
2635
self.agent = Github(auth=Auth.Token(github_token), base_url=base_url)
2736
self.repo = self.agent.get_repo(repo_name)
28-
# NOTE: The org object obtained from `self.repo.organization` has the wrong URL, so we
29-
# retrieve it using `get_organization` instead to get one that isn't broken.
37+
# NOTE: The org object obtained from `self.repo.organization` has the wrong URL,
38+
# so we retrieve it using `get_organization` instead to get one that isn't
39+
# broken.
3040
self.org = self.agent.get_organization(self.repo.organization.login)
3141
self.org_members = {member.login for member in self.org.get_members()}
3242

33-
def thanks_message(self, commit: git.GitCommit) -> str:
43+
def thanks_message(self, commit: git.GitCommit) -> str: # noqa: ANN101
3444
usernames = [
3545
f"@{username}" for username in self.third_party_contributors(commit)
3646
]
@@ -41,18 +51,19 @@ def thanks_message(self, commit: git.GitCommit) -> str:
4151
return template.format(usernames[0])
4252
return template.format(f"{', '.join(usernames[:-1])}, and {usernames[-1]}")
4353

44-
def third_party_contributors(self, commit: git.GitCommit) -> Iterable[str]:
54+
def third_party_contributors(self: Thanker, commit: git.GitCommit) -> Iterable[str]:
4555
for contributor in self.contributors(commit):
4656
if contributor not in self.org_members:
4757
yield contributor
4858

49-
def contributors(self, commit: git.GitCommit) -> Iterable[str]:
59+
def contributors(self: Thanker, commit: git.GitCommit) -> Iterable[str]:
5060
github_commit = self.repo.get_commit(commit.rev)
5161
yield github_commit.author.login
52-
# FIXME: Cannot thank co-authors automatically until `email_to_github_username` is implemented.
53-
# yield from self.co_authors(github_commit.commit.message)
62+
# FIXME: Cannot thank co-authors automatically until `email_to_github_username`
63+
# is implemented.
64+
# yield from self.co_authors(github_commit.commit.message) # noqa: ERA001
5465

55-
def co_authors(self, commit_message: str) -> Iterable[str]:
66+
def co_authors(self: Thanker, commit_message: str) -> Iterable[str]:
5667
co_author_lines = {
5768
line
5869
for line in commit_message.splitlines()
@@ -64,8 +75,10 @@ def co_authors(self, commit_message: str) -> Iterable[str]:
6475
)
6576

6677
# TODO: This method should use memoization - https://pypi.org/project/methodtools/
67-
def email_to_github_username(self, email: str) -> str:
68-
# TODO: Find a reliable way to get the GitHub username linked to a given email address.
69-
# The user search API was tried, but it cannot find many users given their public primary
70-
# GitHub emails. I'm not sure why it is not reliable, or what conditions make it work.
78+
def email_to_github_username(self: Thanker, email: str) -> str:
79+
# TODO: Find a reliable way to get the GitHub username linked to a given email
80+
# address.
81+
# The user search API was tried, but it cannot find many users given their
82+
# public primary GitHub emails. I'm not sure why it is not reliable, or what
83+
# conditions make it work.
7184
raise NotImplementedError

0 commit comments

Comments
 (0)