Skip to content

Commit bba3019

Browse files
committed
feat: inheriting workspace members with path, package and version attributes
1 parent 08f0fb3 commit bba3019

2 files changed

Lines changed: 277 additions & 31 deletions

File tree

commitizen/providers/cargo_provider.py

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ def get(self, document: TOMLDocument) -> str:
3737
def set(self, document: TOMLDocument, version: str) -> None:
3838
_try_get_workspace(document)["package"]["version"] = version
3939

40+
if document.get("workspace"):
41+
# get all workspace members that have a version.workspace = true
42+
members_inheriting = _get_workspace_members(document, self._get_encoding())
43+
44+
# get all workspace dependencies that have a version specified and match a member inheriting
45+
workspace_deps = document["workspace"].get("dependencies", {})
46+
for dep_name, dep_value in workspace_deps.items():
47+
if isinstance(dep_value, str) and (dep_name in members_inheriting):
48+
workspace_deps[dep_name] = version
49+
elif (isinstance(dep_value, dict) and dep_value.get("version", [])):
50+
if dep_value.get("path", "") and dep_value.get("package", ""):
51+
crate_name = dep_value["package"]
52+
else:
53+
crate_name = dep_name
54+
55+
if crate_name in members_inheriting:
56+
dep_value["version"] = version
57+
4058
def set_version(self, version: str) -> None:
4159
super().set_version(version)
4260
if self.lock_file.is_file():
@@ -61,37 +79,7 @@ def set_lock_version(self, version: str) -> None:
6179
cargo_lock_content["package"][i]["version"] = version # type: ignore[index]
6280
break
6381
except NonExistentKey:
64-
workspace = cargo_toml_content.get("workspace", {})
65-
if TYPE_CHECKING:
66-
assert isinstance(workspace, dict)
67-
workspace_members = workspace.get("members", [])
68-
excluded_workspace_members = workspace.get("exclude", [])
69-
members_inheriting: list[str] = []
70-
71-
for member in workspace_members:
72-
for path in glob.glob(member, recursive=True):
73-
if any(
74-
fnmatch.fnmatch(path, pattern)
75-
for pattern in excluded_workspace_members
76-
):
77-
continue
78-
79-
cargo_file = Path(path) / "Cargo.toml"
80-
package_content = parse(
81-
cargo_file.read_text(encoding=self._get_encoding())
82-
).get("package", {})
83-
if TYPE_CHECKING:
84-
assert isinstance(package_content, dict)
85-
try:
86-
if not isinstance(package_content["version"], str):
87-
version_workspace = package_content["version"]["workspace"]
88-
if version_workspace is True:
89-
package_name = package_content["name"]
90-
if TYPE_CHECKING:
91-
assert isinstance(package_name, str)
92-
members_inheriting.append(package_name)
93-
except NonExistentKey:
94-
pass
82+
members_inheriting = _get_workspace_members(cargo_toml_content, self._get_encoding())
9583

9684
for i, package in enumerate(packages):
9785
if package["name"] in members_inheriting:
@@ -110,3 +98,38 @@ def _try_get_workspace(document: TOMLDocument) -> dict:
11098
return workspace
11199
except NonExistentKey:
112100
return document
101+
102+
def _get_workspace_members(cargo_toml_content: TOMLDocument, encoding: str | None) -> list[str]:
103+
workspace = cargo_toml_content.get("workspace", {})
104+
if TYPE_CHECKING:
105+
assert isinstance(workspace, dict)
106+
workspace_members = workspace.get("members", [])
107+
excluded_workspace_members = workspace.get("exclude", [])
108+
members_inheriting: list[str] = []
109+
110+
for member in workspace_members:
111+
for path in glob.glob(member, recursive=True):
112+
if any(
113+
fnmatch.fnmatch(path, pattern)
114+
for pattern in excluded_workspace_members
115+
):
116+
continue
117+
118+
cargo_file = Path(path) / "Cargo.toml"
119+
package_content = parse(
120+
cargo_file.read_text(encoding=encoding)
121+
).get("package", {})
122+
if TYPE_CHECKING:
123+
assert isinstance(package_content, dict)
124+
try:
125+
if not isinstance(package_content["version"], str):
126+
version_workspace = package_content["version"]["workspace"]
127+
if version_workspace is True:
128+
package_name = package_content["name"]
129+
if TYPE_CHECKING:
130+
assert isinstance(package_name, str)
131+
members_inheriting.append(package_name)
132+
except NonExistentKey:
133+
pass
134+
135+
return members_inheriting

tests/providers/test_cargo_provider.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,3 +522,226 @@ def test_cargo_provider_workspace_member_without_workspace_key(
522522
assert file.read_text() == dedent(expected_workspace_toml)
523523
# The lock file should remain unchanged since the member doesn't inherit workspace version
524524
assert lock_file.read_text() == dedent(expected_lock_content)
525+
526+
527+
def test_cargo_provider_inheriting_workspace_member_with_version_in_toml(
528+
config: BaseConfig,
529+
chdir: Path,
530+
):
531+
"""Test workspace member that has version key but no workspace subkey."""
532+
workspace_toml = """\
533+
[workspace]
534+
members = ["inheriting_member"]
535+
536+
[workspace.package]
537+
version = "0.1.0"
538+
539+
[workspace.dependencies]
540+
inheriting_member = "0.1.0"
541+
"""
542+
543+
member_content = """\
544+
[package]
545+
name = "inheriting_member"
546+
version.workspace = true
547+
"""
548+
549+
lock_content = """\
550+
[[package]]
551+
name = "inheriting_member"
552+
version = "0.1.0"
553+
source = "registry+https://github.com/rust-lang/crates.io-index"
554+
checksum = "123abc"
555+
"""
556+
557+
expected_workspace_toml = """\
558+
[workspace]
559+
members = ["inheriting_member"]
560+
561+
[workspace.package]
562+
version = "42.1"
563+
564+
[workspace.dependencies]
565+
inheriting_member = "42.1"
566+
"""
567+
568+
expected_lock_content = """\
569+
[[package]]
570+
name = "inheriting_member"
571+
version = "42.1"
572+
source = "registry+https://github.com/rust-lang/crates.io-index"
573+
checksum = "123abc"
574+
"""
575+
576+
# Create the workspace file
577+
filename = CargoProvider.filename
578+
file = chdir / filename
579+
file.write_text(dedent(workspace_toml))
580+
581+
# Create the member directory and file
582+
os.mkdir(chdir / "inheriting_member")
583+
member_file = chdir / "inheriting_member" / "Cargo.toml"
584+
member_file.write_text(dedent(member_content))
585+
586+
# Create the lock file
587+
lock_filename = CargoProvider.lock_filename
588+
lock_file = chdir / lock_filename
589+
lock_file.write_text(dedent(lock_content))
590+
591+
config.settings["version_provider"] = "cargo"
592+
593+
provider = get_provider(config)
594+
assert isinstance(provider, CargoProvider)
595+
assert provider.get_version() == "0.1.0"
596+
597+
provider.set_version("42.1")
598+
assert file.read_text() == dedent(expected_workspace_toml)
599+
assert lock_file.read_text() == dedent(expected_lock_content)
600+
601+
def test_cargo_provider_inheriting_workspace_member_with_version_dict_in_toml(
602+
config: BaseConfig,
603+
chdir: Path,
604+
):
605+
"""Test workspace member that has version key but no workspace subkey."""
606+
workspace_toml = """\
607+
[workspace]
608+
members = ["inheriting_member"]
609+
610+
[workspace.package]
611+
version = "0.1.0"
612+
613+
[workspace.dependencies]
614+
inheriting_member = { version = "0.1.0" }
615+
"""
616+
617+
member_content = """\
618+
[package]
619+
name = "inheriting_member"
620+
version.workspace = true
621+
"""
622+
623+
lock_content = """\
624+
[[package]]
625+
name = "inheriting_member"
626+
version = "0.1.0"
627+
source = "registry+https://github.com/rust-lang/crates.io-index"
628+
checksum = "123abc"
629+
"""
630+
631+
expected_workspace_toml = """\
632+
[workspace]
633+
members = ["inheriting_member"]
634+
635+
[workspace.package]
636+
version = "42.1"
637+
638+
[workspace.dependencies]
639+
inheriting_member = { version = "42.1" }
640+
"""
641+
642+
expected_lock_content = """\
643+
[[package]]
644+
name = "inheriting_member"
645+
version = "42.1"
646+
source = "registry+https://github.com/rust-lang/crates.io-index"
647+
checksum = "123abc"
648+
"""
649+
650+
# Create the workspace file
651+
filename = CargoProvider.filename
652+
file = chdir / filename
653+
file.write_text(dedent(workspace_toml))
654+
655+
# Create the member directory and file
656+
os.mkdir(chdir / "inheriting_member")
657+
member_file = chdir / "inheriting_member" / "Cargo.toml"
658+
member_file.write_text(dedent(member_content))
659+
660+
# Create the lock file
661+
lock_filename = CargoProvider.lock_filename
662+
lock_file = chdir / lock_filename
663+
lock_file.write_text(dedent(lock_content))
664+
665+
config.settings["version_provider"] = "cargo"
666+
667+
provider = get_provider(config)
668+
assert isinstance(provider, CargoProvider)
669+
assert provider.get_version() == "0.1.0"
670+
671+
provider.set_version("42.1")
672+
assert file.read_text() == dedent(expected_workspace_toml)
673+
assert lock_file.read_text() == dedent(expected_lock_content)
674+
675+
def test_cargo_provider_inheriting_workspace_member_with_version_and_package_in_toml(
676+
config: BaseConfig,
677+
chdir: Path,
678+
):
679+
"""Test workspace member that has version key but no workspace subkey."""
680+
workspace_toml = """\
681+
[workspace]
682+
members = ["mypath/original_name"]
683+
684+
[workspace.package]
685+
version = "0.1.0"
686+
687+
[workspace.dependencies]
688+
renamed_inheriting_member = { version = "0.1.0", path = "mypath/original_name", package = "original_name" }
689+
"""
690+
691+
member_content = """\
692+
[package]
693+
name = "original_name"
694+
version.workspace = true
695+
"""
696+
697+
lock_content = """\
698+
[[package]]
699+
name = "original_name"
700+
version = "0.1.0"
701+
source = "registry+https://github.com/rust-lang/crates.io-index"
702+
checksum = "123abc"
703+
"""
704+
705+
expected_workspace_toml = """\
706+
[workspace]
707+
members = ["mypath/original_name"]
708+
709+
[workspace.package]
710+
version = "42.1"
711+
712+
[workspace.dependencies]
713+
renamed_inheriting_member = { version = "42.1", path = "mypath/original_name", package = "original_name" }
714+
"""
715+
716+
expected_lock_content = """\
717+
[[package]]
718+
name = "original_name"
719+
version = "42.1"
720+
source = "registry+https://github.com/rust-lang/crates.io-index"
721+
checksum = "123abc"
722+
"""
723+
724+
# Create the workspace file
725+
filename = CargoProvider.filename
726+
file = chdir / filename
727+
file.write_text(dedent(workspace_toml))
728+
729+
# Create the member directory and file
730+
os.makedirs(chdir / "mypath/original_name")
731+
member_file = chdir / "mypath/original_name" / "Cargo.toml"
732+
member_file.write_text(dedent(member_content))
733+
734+
# Create the lock file
735+
lock_filename = CargoProvider.lock_filename
736+
lock_file = chdir / lock_filename
737+
lock_file.write_text(dedent(lock_content))
738+
739+
config.settings["version_provider"] = "cargo"
740+
741+
provider = get_provider(config)
742+
assert isinstance(provider, CargoProvider)
743+
assert provider.get_version() == "0.1.0"
744+
745+
provider.set_version("42.1")
746+
assert file.read_text() == dedent(expected_workspace_toml)
747+
assert lock_file.read_text() == dedent(expected_lock_content)

0 commit comments

Comments
 (0)