Skip to content

Commit 4ff25e3

Browse files
fix(providers/cargo): don't crash on workspace member with fixed version
When iterating workspace members in `CargoProvider.set_lock_version`, the code subscripted `package["version"]["workspace"]` inside a try/except block that only caught `NonExistentKey`. If a member's `Cargo.toml` declared a hardcoded version (`version = "x.y.z"`) instead of `version.workspace = true`, `package["version"]` was a tomlkit `String` and the subscript raised `TypeError: string indices must be integers, not 'str'`, which was not caught and propagated as a crash. Replace the exception-driven check with an `isinstance` type guard so the inheritance lookup only runs when `version` is an actual table. Fixes #2001 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a523e55 commit 4ff25e3

2 files changed

Lines changed: 86 additions & 9 deletions

File tree

commitizen/providers/cargo_provider.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ def set_lock_version(self, version: str) -> None:
8282
).get("package", {})
8383
if TYPE_CHECKING:
8484
assert isinstance(package_content, dict)
85-
try:
86-
version_workspace = package_content["version"]["workspace"]
87-
if version_workspace is True:
88-
package_name = package_content["name"]
89-
if TYPE_CHECKING:
90-
assert isinstance(package_name, str)
91-
members_inheriting.append(package_name)
92-
except NonExistentKey:
93-
pass
85+
version_field = package_content.get("version")
86+
if (
87+
isinstance(version_field, dict)
88+
and version_field.get("workspace") is True
89+
):
90+
package_name = package_content["name"]
91+
if TYPE_CHECKING:
92+
assert isinstance(package_name, str)
93+
members_inheriting.append(package_name)
9494

9595
for i, package in enumerate(packages):
9696
if package["name"] in members_inheriting:

tests/providers/test_cargo_provider.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,80 @@ def test_cargo_provider_workspace_member_without_workspace_key(
451451
assert file.read_text() == dedent(expected_workspace_toml)
452452
# The lock file should remain unchanged since the member doesn't inherit workspace version
453453
assert lock_file.read_text() == dedent(expected_lock_content)
454+
455+
456+
def test_cargo_provider_workspace_member_with_fixed_version(
457+
config: BaseConfig,
458+
chdir: Path,
459+
):
460+
"""Regression test for https://github.com/commitizen-tools/commitizen/issues/2001.
461+
462+
A workspace member with a hardcoded ``version = "x.y.z"`` string (rather
463+
than ``version.workspace = true``) used to crash ``set_lock_version`` with
464+
``TypeError: string indices must be integers, not 'str'`` because the code
465+
unconditionally subscripted ``package["version"]["workspace"]``.
466+
"""
467+
workspace_toml = """\
468+
[workspace]
469+
members = ["member_with_fixed_version"]
470+
471+
[workspace.package]
472+
version = "0.1.0"
473+
"""
474+
475+
# Real Cargo syntax for a workspace member that opts out of the
476+
# workspace-inherited version by pinning its own.
477+
member_content = """\
478+
[package]
479+
name = "member_with_fixed_version"
480+
version = "0.9.0"
481+
"""
482+
483+
lock_content = """\
484+
[[package]]
485+
name = "member_with_fixed_version"
486+
version = "0.9.0"
487+
source = "registry+https://github.com/rust-lang/crates.io-index"
488+
checksum = "123abc"
489+
"""
490+
491+
expected_workspace_toml = """\
492+
[workspace]
493+
members = ["member_with_fixed_version"]
494+
495+
[workspace.package]
496+
version = "42.1"
497+
"""
498+
499+
# The pinned member must not be bumped because it does not inherit the
500+
# workspace version.
501+
expected_lock_content = """\
502+
[[package]]
503+
name = "member_with_fixed_version"
504+
version = "0.9.0"
505+
source = "registry+https://github.com/rust-lang/crates.io-index"
506+
checksum = "123abc"
507+
"""
508+
509+
filename = CargoProvider.filename
510+
file = chdir / filename
511+
file.write_text(dedent(workspace_toml))
512+
513+
os.mkdir(chdir / "member_with_fixed_version")
514+
member_file = chdir / "member_with_fixed_version" / "Cargo.toml"
515+
member_file.write_text(dedent(member_content))
516+
517+
lock_filename = CargoProvider.lock_filename
518+
lock_file = chdir / lock_filename
519+
lock_file.write_text(dedent(lock_content))
520+
521+
config.settings["version_provider"] = "cargo"
522+
523+
provider = get_provider(config)
524+
assert isinstance(provider, CargoProvider)
525+
assert provider.get_version() == "0.1.0"
526+
527+
# Must not raise TypeError: string indices must be integers, not 'str'.
528+
provider.set_version("42.1")
529+
assert file.read_text() == dedent(expected_workspace_toml)
530+
assert lock_file.read_text() == dedent(expected_lock_content)

0 commit comments

Comments
 (0)