Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
python-check:
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
platform: [ubuntu-22.04, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down
4 changes: 2 additions & 2 deletions commitizen/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def find_increment(
def update_version_in_files(
current_version: str,
new_version: str,
files: Iterable[str],
version_files: Iterable[str],
*,
check_consistency: bool,
encoding: str,
Expand All @@ -77,7 +77,7 @@ def update_version_in_files(
"""
updated_files = []

for path, pattern in _resolve_files_and_regexes(files, current_version):
for path, pattern in _resolve_files_and_regexes(version_files, current_version):
current_version_found = False
bumped_lines = []

Expand Down
23 changes: 14 additions & 9 deletions commitizen/commands/bump.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,33 +302,38 @@ def __call__(self) -> None:
"[NO_COMMITS_TO_BUMP]\nThe commits found are not eligible to be bumped"
)

files: list[str] = []
updated_files: list[str] = []
dry_run = self.arguments["dry_run"]
if self.changelog_flag:
args = {
changelog_args = {
"unreleased_version": new_tag_version,
"template": self.template,
"extras": self.extras,
"incremental": True,
"dry_run": dry_run,
}
if self.changelog_to_stdout:
changelog_cmd = Changelog(self.config, {**args, "dry_run": True}) # type: ignore[typeddict-item]
changelog_cmd = Changelog(
self.config,
{**changelog_args, "dry_run": True}, # type: ignore[typeddict-item]
)
try:
changelog_cmd()
except DryRunExit:
pass

args["file_name"] = self.file_name
changelog_cmd = Changelog(self.config, args) # type: ignore[arg-type]
changelog_cmd = Changelog(
self.config,
{**changelog_args, "file_name": self.file_name}, # type: ignore[typeddict-item]
)
changelog_cmd()
files.append(changelog_cmd.file_name)
updated_files.append(changelog_cmd.file_name)

# Do not perform operations over files or git.
if dry_run:
raise DryRunExit()

files.extend(
updated_files.extend(
bump.update_version_in_files(
str(current_version),
str(new_version),
Expand Down Expand Up @@ -360,13 +365,13 @@ def __call__(self) -> None:
raise ExpectedExit()

# FIXME: check if any changes have been staged
git.add(*files)
git.add(*updated_files)
c = git.commit(message, args=self._get_commit_args())
if self.retry and c.return_code != 0 and self.changelog_flag:
# Maybe pre-commit reformatted some files? Retry once
logger.debug("1st git.commit error: %s", c.err)
logger.info("1st commit attempt failed; retrying once")
git.add(*files)
git.add(*updated_files)
c = git.commit(message, args=self._get_commit_args())
if c.return_code != 0:
err = c.err.strip() or c.out
Expand Down
3 changes: 2 additions & 1 deletion commitizen/commands/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ def __call__(self) -> None:
raise NotAllowed("--incremental cannot be combined with a rev_range")

# Don't continue if no `file_name` specified.
assert self.file_name
if not self.file_name:
raise NotAllowed("filename is required.")

tags = self.tag_rules.get_version_tags(git.get_tags(), warn=True)
changelog_meta = changelog.Metadata()
Expand Down
99 changes: 54 additions & 45 deletions commitizen/providers/cargo_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
import fnmatch
import glob
from pathlib import Path
from typing import TYPE_CHECKING

import tomlkit
from tomlkit import TOMLDocument, dumps, parse
from tomlkit.exceptions import NonExistentKey
from tomlkit.items import AoT

from commitizen.providers.base_provider import TomlProvider


def matches_exclude(path: str, exclude_patterns: list[str]) -> bool:
for pattern in exclude_patterns:
if fnmatch.fnmatch(path, pattern):
return True
return False


class CargoProvider(TomlProvider):
"""
Cargo version management
Expand All @@ -30,65 +26,78 @@ class CargoProvider(TomlProvider):
def lock_file(self) -> Path:
return Path() / self.lock_filename

def get(self, document: tomlkit.TOMLDocument) -> str:
# If there is a root package, change its version (but not the workspace version)
try:
return document["package"]["version"] # type: ignore[index,return-value]
# Else, bump the workspace version
except tomlkit.exceptions.NonExistentKey:
...
return document["workspace"]["package"]["version"] # type: ignore[index,return-value]
def get(self, document: TOMLDocument) -> str:
out = _try_get_workspace(document)["package"]["version"]
if TYPE_CHECKING:
assert isinstance(out, str)
return out

def set(self, document: tomlkit.TOMLDocument, version: str) -> None:
try:
document["workspace"]["package"]["version"] = version # type: ignore[index]
return
except tomlkit.exceptions.NonExistentKey:
...
document["package"]["version"] = version # type: ignore[index]
def set(self, document: TOMLDocument, version: str) -> None:
_try_get_workspace(document)["package"]["version"] = version

def set_version(self, version: str) -> None:
super().set_version(version)
if self.lock_file.exists():
self.set_lock_version(version)

def set_lock_version(self, version: str) -> None:
cargo_toml_content = tomlkit.parse(self.file.read_text())
cargo_lock_content = tomlkit.parse(self.lock_file.read_text())
packages: tomlkit.items.AoT = cargo_lock_content["package"] # type: ignore[assignment]
cargo_toml_content = parse(self.file.read_text())
cargo_lock_content = parse(self.lock_file.read_text())
packages = cargo_lock_content["package"]

if TYPE_CHECKING:
assert isinstance(packages, AoT)

try:
package_name = cargo_toml_content["package"]["name"] # type: ignore[index]
cargo_package_name = cargo_toml_content["package"]["name"] # type: ignore[index]
if TYPE_CHECKING:
assert isinstance(cargo_package_name, str)
for i, package in enumerate(packages):
if package["name"] == package_name:
if package["name"] == cargo_package_name:
cargo_lock_content["package"][i]["version"] = version # type: ignore[index]
break
except tomlkit.exceptions.NonExistentKey:
workspace_members = cargo_toml_content.get("workspace", {}).get(
"members", []
)
excluded_workspace_members = cargo_toml_content.get("workspace", {}).get(
"exclude", []
)
members_inheriting = []
except NonExistentKey:
workspace = cargo_toml_content.get("workspace", {})
if TYPE_CHECKING:
assert isinstance(workspace, dict)
workspace_members = workspace.get("members", [])
excluded_workspace_members = workspace.get("exclude", [])
members_inheriting: list[str] = []

for member in workspace_members:
for path in glob.glob(member, recursive=True):
if matches_exclude(path, excluded_workspace_members):
if any(
fnmatch.fnmatch(path, pattern)
for pattern in excluded_workspace_members
):
continue

cargo_file = Path(path) / "Cargo.toml"
cargo_toml_content = tomlkit.parse(cargo_file.read_text())
package_content = parse(cargo_file.read_text()).get("package", {})
if TYPE_CHECKING:
assert isinstance(package_content, dict)
try:
version_workspace = cargo_toml_content["package"]["version"][ # type: ignore[index]
"workspace"
]
version_workspace = package_content["version"]["workspace"]
if version_workspace is True:
package_name = cargo_toml_content["package"]["name"] # type: ignore[index]
package_name = package_content["name"]
if TYPE_CHECKING:
assert isinstance(package_name, str)
members_inheriting.append(package_name)
except tomlkit.exceptions.NonExistentKey:
continue
except NonExistentKey:
pass

for i, package in enumerate(packages):
if package["name"] in members_inheriting:
cargo_lock_content["package"][i]["version"] = version # type: ignore[index]

self.lock_file.write_text(tomlkit.dumps(cargo_lock_content))
self.lock_file.write_text(dumps(cargo_lock_content))


def _try_get_workspace(document: TOMLDocument) -> dict:
try:
workspace = document["workspace"]
if TYPE_CHECKING:
assert isinstance(workspace, dict)
return workspace
except NonExistentKey:
return document
Loading