codemagic-ci-cd / cli-tools

Various utilities to managing Android and iOS app builds, code signing, and deployment.
https://codemagic.io/start/
GNU General Public License v3.0
245 stars 42 forks source link

Fix `--credentials` arugment validation for `google-play` #406

Closed priitlatt closed 4 months ago

priitlatt commented 4 months ago

When invoking google-play actions with --credentials that are valid JSON, but not JSON decoded objects, then the command invocation fails unexpectedly with attribute error.

Stacktrace:

$ google-play get-latest-build-number --credentials '1'
Traceback (most recent call last):
  File "/Users/priit/.pyenv/versions/3.12.0/bin/google-play", line 8, in <module>
    sys.exit(GooglePlay.invoke_cli())
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/cli_app.py", line 226, in invoke_cli
    parser, args = cls._resolve_cli_invocation_arg()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/cli_app.py", line 204, in _resolve_cli_invocation_arg
    args = parser.parse_args()
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 1891, in parse_args
    args, argv = self.parse_known_args(args, namespace)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 1924, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2118, in _parse_known_args
    positionals_end_index = consume_positionals(start_index)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2095, in consume_positionals
    take_action(action, args)
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2000, in take_action
    action(self, namespace, argument_values, option_string)
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 1263, in __call__
    subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 1924, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2136, in _parse_known_args
    start_index = consume_optional(start_index)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2076, in consume_optional
    take_action(action, args, option_string)
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 1984, in take_action
    argument_values = self._get_values(action, argument_strings)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2522, in _get_values
    value = self._get_value(action, arg_string)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/argparse.py", line 2555, in _get_value
    result = type_func(arg_string)
             ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/argument/typed_cli_argument.py", line 38, in __call__
    return super().__call__(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/argument/typed_cli_argument.py", line 89, in __init__
    self.value: T = self._parse_value()
                    ^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/argument/typed_cli_argument.py", line 210, in _parse_value
    return super()._parse_value()
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/argument/typed_cli_argument.py", line 130, in _parse_value
    return self._apply_type(value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/cli/argument/typed_cli_argument.py", line 124, in _apply_type
    if not self._is_valid(value):
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/priit/.pyenv/versions/3.12.0/lib/python3.12/site-packages/codemagic/tools/google_play/argument_types.py", line 16, in _is_valid
    return json_content.get("type") == "service_account"
           ^^^^^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'get'

This is not desired and instead we should show a helpful error message about argument validation. With the changes here the very same invocation fails like this:

$ google-play get-latest-build-number --credentials '1'
usage: google-play get-latest-build-number [-h] [--log-stream {stderr,stdout}] [--no-color] [--version] [-s] [-v] --package-name PACKAGE_NAME [--tracks TRACKS [TRACKS ...]]
                                           [--credentials CREDENTIALS]
google-play get-latest-build-number: error: argument --credentials: Provided value "1" is not valid