Skip to content

Commit 83e17f1

Browse files
afrischkgreenbonebot
authored andcommitted
Change: Rust support for workspace.package.version
This is a BREAKING CHANGE to all of those Rust projects using Pontos, if it is used to keep all versions of the member crates in sync with the root crate version. This is discuraged in favor of configuring `[workspace.package.version]` in the root Cargo.toml and `version.workspace = true` in the member crates Cargo.toml to allow for unified metadata like the version. Also Pontos now correctly handles [workspace.package.version] and [package.version]. The latter always has higher priority, if both version properties are set.
1 parent c2656f8 commit 83e17f1

File tree

2 files changed

+245
-117
lines changed

2 files changed

+245
-117
lines changed

pontos/version/commands/_cargo.py

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
# SPDX-License-Identifier: GPL-3.0-or-later
44

55
from pathlib import Path
6-
from typing import Any, Iterator, Literal, Tuple, Union
6+
from typing import Any, Literal, Tuple, Union
77

88
import tomlkit
9-
from tomlkit.items import Table
9+
from tomlkit.toml_document import TOMLDocument
1010

1111
from .._errors import VersionError
1212
from .._version import Version, VersionUpdate
@@ -16,71 +16,100 @@
1616
class CargoVersionCommand(VersionCommand):
1717
project_file_name = "Cargo.toml"
1818

19+
def __has_package_version(self, toml: TOMLDocument):
20+
"""
21+
Checks if the 'package' table contains a 'version'.
22+
"""
23+
# get a pure python object (recursively)
24+
toml_dict = toml.unwrap()
25+
return "package" in toml_dict and "version" in toml_dict["package"]
26+
27+
def __has_workspace_package_version(self, toml: TOMLDocument):
28+
"""
29+
Checks if the 'workspace.package' table contains a 'version'.
30+
"""
31+
# get a pure python object (recursively)
32+
toml_dict = toml.unwrap()
33+
return (
34+
"workspace" in toml_dict
35+
and "package" in toml_dict["workspace"]
36+
and "version" in toml_dict["workspace"]["package"]
37+
)
38+
1939
def __as_project_document(
2040
self, origin: Path
21-
) -> Iterator[Tuple[Path, tomlkit.TOMLDocument],]:
41+
) -> Tuple[Path, tomlkit.TOMLDocument]:
2242
"""
23-
Parse the given origin and yields a tuple of path to a
24-
Cargo.toml that contains a version
43+
Parse the given origin and returns a tuple of path to a
44+
Cargo.toml that contains a version.
2545
Version should be in the table package or workspace.package
2646
2747
If the origin is invalid toml than it will raise a VersionError.
2848
"""
2949
version: Any = None
3050
content = origin.read_text(encoding="utf-8")
3151
content = tomlkit.parse(content)
32-
package = content.get("package")
33-
workspace = content.get("workspace")
34-
if not isinstance(package, Table) and isinstance(workspace, Table):
35-
package = workspace.get("package")
36-
if isinstance(package, Table):
37-
version = package.get("version", "")
52+
if self.__has_workspace_package_version(content):
53+
version = content.get("workspace").get("package").get("version") # type: ignore[union-attr]
54+
55+
if self.__has_package_version(content):
56+
version = content.get("package").get("version") # type: ignore[union-attr]
57+
3858
if version:
39-
yield (origin, content)
59+
return (origin, content)
4060
else:
41-
# check sub directories for toml files with version
42-
if isinstance(workspace, Table):
43-
members = workspace.get("members")
44-
if members:
45-
for member in members:
46-
yield from self.__as_project_document(
47-
origin.parent / member / self.project_file_name
48-
)
49-
return None
61+
raise VersionError(
62+
f"No {origin} file found. This file is required for pontos."
63+
)
5064

5165
def update_version(
5266
self, new_version: Version, *, force: bool = False
5367
) -> VersionUpdate:
5468
try:
5569
previous_version = self.get_current_version()
56-
5770
if not force and new_version == previous_version:
5871
return VersionUpdate(previous=previous_version, new=new_version)
5972
except VersionError:
6073
# just ignore current version and override it
6174
previous_version = None
6275

63-
changed_files = []
64-
for project_path, project in self.__as_project_document(
76+
project_path, project = self.__as_project_document(
6577
self.project_file_path
66-
):
78+
)
79+
80+
if self.__has_workspace_package_version(project):
81+
# Set the version for all members of the workspace. Members of the
82+
# workspace should use `version.workspace=true` in the 'package' table,
83+
# if they are released together with the parent crate.
84+
project["workspace"]["package"]["version"] = str(new_version) # type: ignore[index] # noqa: E501
85+
86+
if self.__has_package_version(project):
87+
# Set the 'version' of the 'package' table for the parent crate
6788
project["package"]["version"] = str(new_version) # type: ignore[index] # noqa: E501
68-
project_path.write_text(tomlkit.dumps(project))
69-
changed_files.append(project_path)
89+
90+
project_path.write_text(tomlkit.dumps(project))
7091
return VersionUpdate(
7192
previous=previous_version,
7293
new=new_version,
73-
changed_files=changed_files,
94+
changed_files=[project_path],
7495
)
7596

7697
def get_current_version(self) -> Version:
77-
(_, document) = next(self.__as_project_document(self.project_file_path))
78-
try:
79-
version = document["package"]["version"] # type: ignore[index, arg-type]
80-
except KeyError:
98+
(_, document) = self.__as_project_document(self.project_file_path)
99+
100+
version: Any = None
101+
if self.__has_workspace_package_version(document):
81102
version = document["workspace"]["package"]["version"] # type: ignore[index, arg-type]
103+
104+
if self.__has_package_version(document):
105+
# If the 'package' table has a 'version', it always has precedence over the
106+
# 'version' in the 'workspace.package' table (they are assumed to be equal, if
107+
# managed by pontos)
108+
version = document["package"]["version"] # type: ignore[index, arg-type]
109+
82110
if isinstance(version, str):
83111
current_version = self.versioning_scheme.parse_version(version)
112+
84113
return self.versioning_scheme.from_version(current_version)
85114

86115
def verify_version(

0 commit comments

Comments
 (0)