diff --git a/CHANGELOG.md b/CHANGELOG.md index 3df71289..a9abbfcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - When the API or a proxy answers the SAML IdP request with an HTML page or a JSON value that is not an object, `cloudsmith auth` now shows "Failed to authenticate via SAML!" with the reason. Before this fix, the CLI stopped with a `JSONDecodeError` or an `AttributeError`. The 2FA code exchange and the SAML token refresh now also reject a response that is not a JSON object. The 2FA code exchange also rejects a response without an access token. - List commands that return no results now print `Results: 0 `, not `Results: 1-0 (0) of 0 (page: 1/1, ...)`. When the API response has no pagination headers, list commands print only the result count, not `of None`. - An API request no longer waits without a limit when the API host accepts the connection but does not reply. A request now fails when it cannot connect in 30 seconds, or when it gets no data for 90 seconds. The API CDN waits 60 seconds for the API, so the CLI does not stop a slow request before the CDN does. If a request fails, the CLI retries it up to 6 times by default (`--error-retry-max`). A POST request has only the 30-second connection timeout, because a retry after a read timeout can create a second entry. File uploads and downloads do not change. +- Every command, including `--help`, no longer stops with `TypeError` or `AttributeError` about `ColorMode` when the installed `click` is older than 8.2. The CLI needs `click` 8.2 or later, but the install of another package can replace it with an older `click`. - `cloudsmith credential-helper install cargo` no longer replaces a `credential-provider` that you set on a Cloudsmith registry in `config.toml`. The install keeps your provider and shows a warning that names the registry. Previously, the install replaced your provider, and `uninstall cargo` then removed it. - `cloudsmith credential-helper uninstall pnpm` now removes the `pnpm-credential-cloudsmith` launcher when the `.npmrc` file does not exist. Previously, it printed `.npmrc file doesn't exist, nothing to do` and did not remove the launcher. The command does not create the `.npmrc` file. - `cloudsmith credential-helper install` and `uninstall` no longer replace a Docker `config.json` or a Cargo `config.toml` that does not parse. Previously, the CLI read such a file as empty and wrote over it, so your settings were lost. Now the command stops with an error that names the file, and it does not write to the file. Correct or remove the file. Then run the command again. diff --git a/cloudsmith_cli/cli/decorators.py b/cloudsmith_cli/cli/decorators.py index f2d7e80b..e2022716 100644 --- a/cloudsmith_cli/cli/decorators.py +++ b/cloudsmith_cli/cli/decorators.py @@ -244,7 +244,9 @@ def common_cli_output_options(f): "--color", envvar="CLOUDSMITH_COLOR", default="auto", - type=click.Choice(ColorMode, case_sensitive=False), + type=click.Choice( + [mode.name.lower() for mode in ColorMode], case_sensitive=False + ), help="Control whether ANSI colour output is used: auto, always or never.", ) @click.option( @@ -299,7 +301,7 @@ def wrapper(ctx, *args, **kwargs): "CLOUDSMITH_FORCE_COLOR": kwargs.pop("force_color_env"), "TERM": kwargs.pop("term_env"), }, - kwargs.pop("color"), + ColorMode[kwargs.pop("color").upper()], TTYMode.ENABLED if sys.stdout.isatty() else TTYMode.DISABLED, ) diff --git a/cloudsmith_cli/cli/tests/test_decorators.py b/cloudsmith_cli/cli/tests/test_decorators.py index c57d95e7..4ca6be3d 100644 --- a/cloudsmith_cli/cli/tests/test_decorators.py +++ b/cloudsmith_cli/cli/tests/test_decorators.py @@ -13,6 +13,7 @@ from ..commands.main import main from ..config import Options from ..decorators import ( + common_cli_output_options, common_package_action_options, initialise_api, initialise_session, @@ -374,3 +375,16 @@ def command(opts): assert result.exit_code == 2, result.output assert "Invalid value for '--api-headers'" in result.output + + +def test_color_choices_are_text_for_click_before_8_2(): + @click.command() + @common_cli_output_options + def command(opts): + click.echo(click.get_current_context().color) + + color_option = next(param for param in command.params if param.name == "color") + result = click.testing.CliRunner().invoke(command, ["--color", "NEVER"]) + + assert all(isinstance(choice, str) for choice in color_option.type.choices) + assert result.output == "False\n"