Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify Google API clients for Google Play and Firebase #443

Merged
merged 29 commits into from
Feb 21, 2025

Conversation

priitlatt
Copy link
Contributor

@priitlatt priitlatt commented Feb 13, 2025

Unify Google APIs usage under a common package codemagic.google which can be used for both firebase-app-distribution and google-play tools.

Note

This PR contains some breaking changes to internal Python APIs, but all CLI usage remains backwards compatible.

Updated actions:

  • firebase-app-distribution get-latest-build-version
  • firebase-app-distribution releases list
  • google-play get-latest-build-number
  • google-play tracks get
  • google-play tracks list
  • google-play tracks promote-release

For more detailed list of changes refer to CHANGELOG.md.

QA

Full feature parity with current production version is ensured on updated actions.

@priitlatt priitlatt marked this pull request as ready for review February 19, 2025 14:24
_OMIT_KEYS: Tuple[str, ...] = ("_raw",)
_OMIT_IF_NONE_KEYS: Tuple[str, ...] = tuple()

class AppleDictSerializable(DictSerializable):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DictSerializable is now defined in codemagic.models. It is identical to what is here apart from how datetime objects are serialized.

Comment on lines +37 to +44
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
deprecated_environment_variable_key = getattr(cls, "deprecated_environment_variable_key", None)
environment_variable_key = getattr(cls, "environment_variable_key", None)
if deprecated_environment_variable_key and not environment_variable_key:
raise ValueError(
"deprecated_environment_variable_key can only be set if environment_variable_key is also set",
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard check to ensure that deprecated environment variable keys can only be defined in case environment_variable_key is defined to avoid developer errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaces GooglePlayDeveloperAPIClient from codemagic.google_play.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally identical to old ReleaseManager that was defined in src/codemagic/google/resource_managers/release_manager.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Google services are different enough that such an abstraction is just a burden. Request execution lives now in the base ResourceManager class but request building and response handling is left for manager implementations.

def resource_type(self) -> Type[ResourceT]:
raise NotImplementedError()

def _execute_request(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used to be part of ActingManagerMixin which is removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there are naming conflicts between different services, then it is better to isolate service specific definitions into relevant namespaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this was very Firebase specific and could not be extended to other APIs. It was removed altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Resource definition combines old implementations of Firebase and Google Play resources so that all needs are covered. String representation is modified slightly to be easier to read by following some patterns from Yaml.


from codemagic import cli


class CredentialsArgument(cli.EnvironmentArgumentValue[str]):
environment_variable_key = "GCLOUD_SERVICE_ACCOUNT_CREDENTIALS"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment variable name GCLOUD_SERVICE_ACCOUNT_CREDENTIALS is ambiguous and can be confusing. Use GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS instead, but keep the old version also functional with deprecation warning.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package codemagic.google.resource_managers was refactored to codemagic.google.services to better reflect how Google organizes their APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed at all. Service can build the parent URI from explicit project number and app ID arguments without another layer of abstraction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That used to be ReleasesManager before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method _execute_request from here was moved to new base service class ResourceService.

Copy link
Contributor

@fran-tirapu fran-tirapu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good refactoring job and nice comments to help the reviewing job.
I left couple of comments.

class Resource(ABC):
__google_api_label__: ClassVar[Optional[str]] = None
class Resource(DictSerializable, JsonSerializable):
@staticmethod
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any other purpose than the str representation of the object for all these code?
Now the object is DictSerializable/JsonSerializable so probably we can get rid of all this and just use a prettify version of the dict/json.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Base Resource class is indeed mostly just to have a nice string representation of the object which is displayed to the user.

Screenshot

Screenshot 2025-02-20 at 15 00 03

JsonSerializable is just nice to have and adds a convenience method resource.json(**dump_options), which is just a shorthand for json.dumps(resource.dict(), **dump_options). As it exists and is also widely used for App Store Connect resources, then I don't see any reasons not to have it here.

DictSerializable does a little more than just dataclasses.asdict though. It generates a dictionary representation of the resource in a way that the dictionary can be directly passed along to different API calls which require the dictionary to be JSON serializable. That is, the whole dictionary is recursively transformed to contain only basic JSON serializable types. For example ISO8601 representation is used for datetimes, enums are converted to their respective values etc.

Co-authored-by: fran-tirapu <129050941+fran-tirapu@users.noreply.github.com>
@priitlatt priitlatt merged commit 6ac7b77 into master Feb 21, 2025
13 checks passed
@priitlatt priitlatt deleted the refacor/unify-google-api-clients branch February 21, 2025 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants