From e9878532dd58cd80de5a677f2741c40e53650b22 Mon Sep 17 00:00:00 2001 From: James Troup Date: Wed, 21 Oct 2026 00:30:17 +0100 Subject: [PATCH 1/2] chore: Release 0.5.39.1 --- NEWS.md | 14 ++++++++++++++ pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5e10330..ee2b6f6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,17 @@ +## v0.5.39.1 + +### Features + +### Changes + +- **Dependency Update**: Upgraded certifi to 2026.10.19 to fix [GHSA-6q48-6c7w-9gw2](https://github.com/advisories/GHSA-6q48-6c7w-9gw2) + +### Fixes + +- **Dump**: `sinistral dump` now loads the Terraform provider before it runs, so it no longer fails with `AttributeError: 'NoneType' object has no attribute 'initialize'` + +### Other + ## v0.5.39 ### Features diff --git a/pyproject.toml b/pyproject.toml index 69b8230..dc3534b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "stacklet.client.sinistral" -version = "0.5.39" +version = "0.5.39.1" description = "Sinistral CLI" maintainers = [ { name = "Stacklet Engineering", email = "foss+sinistral-cli@stacklet.io" } ] authors = [ { name = "Stacklet Engineering", email = "foss+sinistral-cli@stacklet.io" } ] diff --git a/uv.lock b/uv.lock index 9cb551d..a8dd3f4 100644 --- a/uv.lock +++ b/uv.lock @@ -2118,7 +2118,7 @@ wheels = [ [[package]] name = "stacklet-client-sinistral" -version = "0.5.39" +version = "0.5.39.1" source = { editable = "." } dependencies = [ { name = "boto3" }, From 0d0d3de62cc3e86669e55c8529adb2984cbd1b16 Mon Sep 17 00:00:00 2001 From: James Troup Date: Wed, 21 Oct 2026 00:43:14 +0100 Subject: [PATCH 2/2] chore: address Cubic PR review feedback --- NEWS.md | 2 ++ pyproject.toml | 2 +- scripts/upgrade.py | 13 +++++--- tests/test_upgrade_script.py | 64 ++++++++++++++++++++++++++++++++++++ uv.lock | 13 ++------ 5 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 tests/test_upgrade_script.py diff --git a/NEWS.md b/NEWS.md index ee2b6f6..8feb932 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,8 @@ ### Other +--- + ## v0.5.39 ### Features diff --git a/pyproject.toml b/pyproject.toml index dc3534b..b0c482f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,12 +32,12 @@ dev = [ "ipdb>=0.13.13,<0.14", "jsonref>=1.1.0,<2", "moto[cognitoidp]>=5,<6", + "packaging>=26,<27", "pre-commit>=4.3.0,<5", "pytest-cov>=7,<8", "pytest>=8,<9", "python-jose>=3.3.0,<4", "ruff>=0.13.0", - "semver>=3.0.4,<4", "tomlkit>=0.13.2,<0.14", ] diff --git a/scripts/upgrade.py b/scripts/upgrade.py index cde7f13..72b0cb6 100644 --- a/scripts/upgrade.py +++ b/scripts/upgrade.py @@ -1,9 +1,10 @@ import sys import click -import semver import tomlkit +from packaging.version import Version + @click.group() def cli(): @@ -18,28 +19,30 @@ def cli(): @click.option("--bump-major", is_flag=True, default=False) def upgrade(bump_patch, bump_minor, bump_major): if sum([bump_patch, bump_minor, bump_major]) != 1: - click.echo("Only one of --bump-patch/mintor/major may be selected") + click.echo("Only one of --bump-patch/minor/major may be selected") sys.exit(1) with open("pyproject.toml") as f: pyproject = tomlkit.load(f) current = pyproject["project"]["version"] - current_parsed = semver.VersionInfo.parse(current) + current_parsed = Version(str(current)) major = current_parsed.major minor = current_parsed.minor - patch = current_parsed.patch + patch = current_parsed.micro if bump_patch: patch += 1 elif bump_minor: minor += 1 + patch = 0 elif bump_major: major += 1 + minor = patch = 0 upgraded = ".".join([str(x) for x in (major, minor, patch)]) - click.echo(f"sinistral-cli: {current_parsed} -> {upgraded}") + click.echo(f"sinistral-cli: {current} -> {upgraded}") pyproject["project"]["version"] = upgraded with open("pyproject.toml", "w+") as f: diff --git a/tests/test_upgrade_script.py b/tests/test_upgrade_script.py new file mode 100644 index 0000000..61f6637 --- /dev/null +++ b/tests/test_upgrade_script.py @@ -0,0 +1,64 @@ +# Copyright Stacklet, Inc. +# SPDX-License-Identifier: Apache-2.0 +import importlib.util + +from pathlib import Path + +import pytest +import tomlkit + +from click.testing import CliRunner + + +SCRIPT = Path(__file__).parent.parent / "scripts" / "upgrade.py" + + +@pytest.fixture +def upgrade_cli(): + spec = importlib.util.spec_from_file_location("upgrade", SCRIPT) + assert spec and spec.loader + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module.cli + + +def write_pyproject(path, version): + (path / "pyproject.toml").write_text(f'[project]\nversion = "{version}"\n') + + +def read_version(path): + return tomlkit.loads((path / "pyproject.toml").read_text())["project"]["version"] + + +@pytest.mark.parametrize( + "current,flag,expected", + [ + ("0.5.39", "--bump-patch", "0.5.40"), + ("0.5.39", "--bump-minor", "0.6.0"), + ("0.5.39", "--bump-major", "1.0.0"), + ("0.5.39.1", "--bump-patch", "0.5.40"), + ("0.5.39.1", "--bump-minor", "0.6.0"), + ("0.5.39.1", "--bump-major", "1.0.0"), + ], +) +def test_upgrade_bumps_version(upgrade_cli, tmp_path, monkeypatch, current, flag, expected): + write_pyproject(tmp_path, current) + monkeypatch.chdir(tmp_path) + + result = CliRunner().invoke(upgrade_cli, ["upgrade", flag]) + + assert result.exit_code == 0, result.output + assert f"{current} -> {expected}" in result.output + assert read_version(tmp_path) == expected + + +@pytest.mark.parametrize("flags", [[], ["--bump-patch", "--bump-minor"]]) +def test_upgrade_requires_exactly_one_flag(upgrade_cli, tmp_path, monkeypatch, flags): + write_pyproject(tmp_path, "0.5.39") + monkeypatch.chdir(tmp_path) + + result = CliRunner().invoke(upgrade_cli, ["upgrade", *flags]) + + assert result.exit_code == 1 + assert "Only one of --bump-patch/minor/major may be selected" in result.output + assert read_version(tmp_path) == "0.5.39" diff --git a/uv.lock b/uv.lock index a8dd3f4..107b0ae 100644 --- a/uv.lock +++ b/uv.lock @@ -2071,15 +2071,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl", hash = "sha256:d8168eccca828cbb2cd573675333f3bddd254313a9c42494b84c76b539e8ba25", size = 90216, upload-time = "2026-07-22T19:30:43.251Z" }, ] -[[package]] -name = "semver" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/f5/e1dfe8e1d91c54ce212fd93916eb01fd1c590f413be0a0978c39a97aa1bb/semver-3.1.0.tar.gz", hash = "sha256:14bc073439513d7773662a338f4db9829cf16c12b74b9568e2d2689975fbd7fc", size = 304162, upload-time = "2026-09-12T18:38:14.045Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/02/bce7a1d70e9d0f6ea8623c16386138c251b5855af6cd3a11433d3fba4e66/semver-3.1.0-py3-none-any.whl", hash = "sha256:6e4998f8b4762acdfea85f9bfd5b4032e0bb50038dc04bf82011b42d5d1145c5", size = 18783, upload-time = "2026-09-12T18:38:12.457Z" }, -] - [[package]] name = "sentry-sdk" version = "2.72.0" @@ -2140,13 +2131,13 @@ dev = [ { name = "ipdb" }, { name = "jsonref" }, { name = "moto", extra = ["cognitoidp"] }, + { name = "packaging" }, { name = "pre-commit", version = "4.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "pre-commit", version = "4.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "python-jose" }, { name = "ruff" }, - { name = "semver" }, { name = "tomlkit" }, ] @@ -2171,12 +2162,12 @@ dev = [ { name = "ipdb", specifier = ">=0.13.13,<0.14" }, { name = "jsonref", specifier = ">=1.1.0,<2" }, { name = "moto", extras = ["cognitoidp"], specifier = ">=5,<6" }, + { name = "packaging", specifier = ">=26,<27" }, { name = "pre-commit", specifier = ">=4.3.0,<5" }, { name = "pytest", specifier = ">=8,<9" }, { name = "pytest-cov", specifier = ">=7,<8" }, { name = "python-jose", specifier = ">=3.3.0,<4" }, { name = "ruff", specifier = ">=0.13.0" }, - { name = "semver", specifier = ">=3.0.4,<4" }, { name = "tomlkit", specifier = ">=0.13.2,<0.14" }, ]