From 0c68b60dbb66912dd20734df402515107c0a6167 Mon Sep 17 00:00:00 2001 From: Siva Mahadevan Date: Mon, 5 Jan 2026 13:27:50 -0500 Subject: [PATCH] chore: upgrade click to ~8.3.0 Necessary changes due to this upgrade: * Minimum python version has been bumped to oldest currently supported version 3.10. Versions 3.8 and 3.9 are officially EOL. * `test_main_no_args_passes_w_help_text` testcase fixed to reflect exit code of 2 as mentioned in https://github.com/pallets/click/releases/tag/8.2.0 release notes * `tests/e2e/cmd_config/test_generate_config.py` testcases fixed to use `stdout` for LHS vs RHS diffing * `CliRunner` construction fixed to reflect `mix_stderr` being removed in click 8.2.0 as mentioned in https://github.com/pallets/click/releases/tag/8.2.0 release notes --- .github/copilot-instructions.md | 10 +++++----- .github/workflows/ci.yml | 4 ++-- .github/workflows/cicd.yml | 4 ++-- .github/workflows/manual.yml | 14 -------------- .github/workflows/validate.yml | 2 +- pyproject.toml | 12 +++++------- src/semantic_release/cli/commands/main.py | 4 ++-- tests/conftest.py | 4 ++-- tests/e2e/cmd_config/test_generate_config.py | 12 ++++++------ tests/e2e/test_main.py | 2 +- 10 files changed, 26 insertions(+), 42 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 97a92c06a..19ec5894b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -24,7 +24,7 @@ tag and annotating releases on a remote Git server with version-specific release ### Installation -Requires 3.9+ for development dependencies, but runtime supports 3.8+. +Requires 3.10+ for development dependencies and runtime. ```bash # Set up for development @@ -499,10 +499,10 @@ itself to perform the release steps. The release process includes: ## Python Version Support -- Runtime Minimum: Python 3.8 -- Development Dependencies: Python 3.9+ -- Tested on: Python 3.8, 3.14 -- Target version for type checking: Python 3.8 +- Runtime Minimum: Python 3.10 +- Development Dependencies: Python 3.10+ +- Tested on: Python 3.10, 3.14 +- Target version for type checking: Python 3.10 ## Dependencies to Know diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d7930dfc..8b571d26e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,11 +90,11 @@ jobs: # It was a bit of overkill before testing every minor version, and since this project is all about # SemVer, we should expect Python to adhere to that model to. Therefore Only test across 2 OS's but # the lowest supported minor version and the latest stable minor version (just in case). - python-versions-linux: '["3.8", "3.14"]' + python-versions-linux: '["3.10", "3.14"]' # Since the test suite takes ~4 minutes to complete on windows, and windows is billed higher # we are only going to run it on the oldest version of python we support. The older version # will be the most likely area to fail as newer minor versions maintain compatibility. - python-versions-windows: '["3.8"]' + python-versions-windows: '["3.10"]' files-changed: ${{ needs.eval-changes.outputs.any-file-changes }} build-files-changed: ${{ needs.eval-changes.outputs.build-changes }} ci-files-changed: ${{ needs.eval-changes.outputs.ci-changes }} diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 49d5f7cf4..d921998f2 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -76,8 +76,8 @@ jobs: # It was a bit of overkill before testing every minor version, and since this project is all about # SemVer, we should expect Python to adhere to that model to. Therefore Only test across 2 OS's but # the lowest supported minor version and the latest stable minor version. - python-versions-linux: '["3.8", "3.14"]' - python-versions-windows: '["3.8", "3.14"]' + python-versions-linux: '["3.10", "3.14"]' + python-versions-windows: '["3.10", "3.14"]' files-changed: ${{ needs.eval-changes.outputs.any-file-changes }} build-files-changed: ${{ needs.eval-changes.outputs.build-changes }} ci-files-changed: ${{ needs.eval-changes.outputs.ci-changes }} diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 67d256fea..ab19e83a3 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -39,16 +39,6 @@ on: type: boolean required: true default: true - python3-9: - description: 'Test Python 3.9?' - type: boolean - required: true - default: true - python3-8: - description: 'Test Python 3.8?' - type: boolean - required: true - default: true # default token permissions = none @@ -78,8 +68,6 @@ jobs: import json, os version_list = list(filter(None, [ - "3.8" if str(os.getenv("INPUT_PY3_8", False)).lower() == str(True).lower() else None, - "3.9" if str(os.getenv("INPUT_PY3_9", False)).lower() == str(True).lower() else None, "3.10" if str(os.getenv("INPUT_PY3_10", False)).lower() == str(True).lower() else None, "3.11" if str(os.getenv("INPUT_PY3_11", False)).lower() == str(True).lower() else None, "3.12" if str(os.getenv("INPUT_PY3_12", False)).lower() == str(True).lower() else None, @@ -105,8 +93,6 @@ jobs: - name: Evaluate | Generate Test Matrix id: test-matrix env: - INPUT_PY3_8: ${{ inputs.python3-8 }} - INPUT_PY3_9: ${{ inputs.python3-9 }} INPUT_PY3_10: ${{ inputs.python3-10 }} INPUT_PY3_11: ${{ inputs.python3-11 }} INPUT_PY3_12: ${{ inputs.python3-12 }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4ee55db53..1d2a6c9e7 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -77,7 +77,7 @@ permissions: {} env: - LOWEST_PYTHON_VERSION: '3.8' + LOWEST_PYTHON_VERSION: '3.10' COMMON_PYTHON_VERSION: '3.11' diff --git a/pyproject.toml b/pyproject.toml index 19b636cb7..559f0ba3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,13 +8,11 @@ build-backend = "setuptools.build_meta" name = "python-semantic-release" version = "10.5.3" description = "Automatic Semantic Versioning for Python projects" -requires-python = "~= 3.8" +requires-python = ">=3.10" license = { text = "MIT" } classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -27,9 +25,9 @@ authors = [ { name = "codejedi365", email = "codejedi365@gmail.com" }, ] dependencies = [ - "click ~= 8.1.0", + "click ~= 8.3.0", "click-option-group ~= 0.5", - "gitpython ~= 3.0", + "gitpython ~= 3.1", "requests ~= 2.25", "jinja2 ~= 3.1", "python-gitlab >= 4.0.0, < 7.0.0", @@ -173,11 +171,11 @@ commands = [testenv:ruff] deps = .[dev] commands = - ruff check . --statistics --output-format=text + ruff check . --statistics """ [tool.mypy] -python_version = "3.8" +python_version = "3.10" show_column_numbers = true show_error_context = true pretty = true diff --git a/src/semantic_release/cli/commands/main.py b/src/semantic_release/cli/commands/main.py index c10d3f647..b0ebc262c 100644 --- a/src/semantic_release/cli/commands/main.py +++ b/src/semantic_release/cli/commands/main.py @@ -30,8 +30,8 @@ ] -class Cli(click.MultiCommand): - """Root MultiCommand for the semantic-release CLI""" +class Cli(click.Group): + """Root Group for the semantic-release CLI""" class SubCmds(Enum): """Subcommand import definitions""" diff --git a/tests/conftest.py b/tests/conftest.py index df4e2f82d..da72c4bd1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -195,7 +195,7 @@ def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item @pytest.fixture def cli_runner() -> CliRunner: - return CliRunner(mix_stderr=False) + return CliRunner() @pytest.fixture(scope="session") @@ -211,7 +211,7 @@ def _run_cli( # Prevent logs from being propagated to the root logger (pytest) logger.propagate = False - cli_runner = CliRunner(mix_stderr=False) + cli_runner = CliRunner() env_vars = {**clean_os_environment, **(env or {})} args = ["-vv", *(argv or [])] diff --git a/tests/e2e/cmd_config/test_generate_config.py b/tests/e2e/cmd_config/test_generate_config.py index a9db934ea..fe3174d43 100644 --- a/tests/e2e/cmd_config/test_generate_config.py +++ b/tests/e2e/cmd_config/test_generate_config.py @@ -51,11 +51,11 @@ def test_generate_config_toml( # Evaluate: Check that the command ran successfully and that the output matches the expected configuration assert_successful_exit_code(result, cli_cmd) - assert expected_config_as_str == result.output.strip() + assert expected_config_as_str == result.stdout.strip() # Setup: Write the generated configuration to a file config_file = "releaserc.toml" - example_project_dir.joinpath(config_file).write_text(result.output) + example_project_dir.joinpath(config_file).write_text(result.stdout) # Act: Validate that the generated config is a valid configuration for PSR cli_cmd = [ @@ -93,11 +93,11 @@ def test_generate_config_json( # Evaluate: Check that the command ran successfully and that the output matches the expected configuration assert_successful_exit_code(result, cli_cmd) - assert expected_config_as_str == result.output.strip() + assert expected_config_as_str == result.stdout.strip() # Setup: Write the generated configuration to a file config_file = "releaserc.json" - example_project_dir.joinpath(config_file).write_text(result.output) + example_project_dir.joinpath(config_file).write_text(result.stdout) # Act: Validate that the generated config is a valid configuration for PSR cli_cmd = [ @@ -144,7 +144,7 @@ def test_generate_config_pyproject_toml( # Evaluate: Check that the command ran successfully and that the output matches the expected configuration assert_successful_exit_code(result, cli_cmd) - assert expected_config_as_str == result.output.strip() + assert expected_config_as_str == result.stdout.strip() # Setup: Write the generated configuration to a file example_pyproject_toml.write_text( @@ -152,7 +152,7 @@ def test_generate_config_pyproject_toml( "\n\n", [ example_pyproject_toml.read_text(encoding="utf-8").strip(), - result.output, + result.stdout, ], ) ) diff --git a/tests/e2e/test_main.py b/tests/e2e/test_main.py index 4e1df87e0..06e25fb29 100644 --- a/tests/e2e/test_main.py +++ b/tests/e2e/test_main.py @@ -65,7 +65,7 @@ def test_main_no_args_passes_w_help_text(): cli_cmd = [MAIN_PROG_NAME] result = CliRunner().invoke(main, prog_name=cli_cmd[0]) - assert_successful_exit_code(result, cli_cmd) + assert_exit_code(2, result, cli_cmd) assert "Usage: " in result.output