Repository: codemagic-ci-cd/cli-tools (language: python)

Issue:
TypeError when auto-promoting Google Play channel with release notes 
My codemagic pipeline is falling over after setting the new release_promotion configuration to auto-promote internal builds to the alpha channel. I reproduced this locally when running the promote-release command directly.

```
google-play tracks promote-release --source-track internal --target-track alpha --package-name com.placeholder.dev --release-status completed --verbose
/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py:34: NotOpenSSLWarning: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020
  warnings.warn(
[15:29:22] DEBUG > Create an edit for the package 'com.placeholder.dev'
[15:29:23] DEBUG > Created edit {'id': '10487428624515697734', 'expiryTimeSeconds': '1697732962'} for package 'com.placeholder.dev'
[15:29:23] DEBUG > Get track 'internal' for package 'com.placeholder.dev' using edit 10487428624515697734
[15:29:23] DEBUG > Got track 'internal' for package 'com.placeholder.dev': {'track': 'internal', 'releases': [{'name': '0.1.36', 'versionCodes': ['386'], 'releaseNotes': [{'language': 'en-US', 'text': '* Release notes\n\nwith some new lines'}], 'status': 'completed'}]}
[15:29:23] DEBUG > Delete the edit '10487428624515697734' for the package 'com.placeholder.dev'
[15:29:23] DEBUG > Deleted edit 10487428624515697734 for package 'com.placeholder.dev'
[15:29:23] DEBUG > Create an edit for the package 'com.placeholder.dev'
[15:29:24] DEBUG > Created edit {'id': '13198323921870656191', 'expiryTimeSeconds': '1697732964'} for package 'com.placeholder.dev'
[15:29:24] DEBUG > Get track 'alpha' for package 'com.placeholder.dev' using edit 13198323921870656191
[15:29:24] DEBUG > Got track 'alpha' for package 'com.placeholder.dev': {'track': 'alpha', 'releases': [{'name': '0.1.36', 'versionCodes': ['359'], 'releaseNotes': [{'language': 'en-US', 'text': '* Release notes\n\nwith some new lines'}], 'status': 'completed'}]}
[15:29:24] DEBUG > Delete the edit '13198323921870656191' for the package 'com.placeholder.dev'
[15:29:25] DEBUG > Deleted edit 13198323921870656191 for package 'com.placeholder.dev'
[15:29:25] WARNING > Executing GooglePlay action tracks failed unexpectedly. Detailed logs are available at "/var/folders/cd/l74ls6v54ds9k99wjsrs6hlc0000gn/T/codemagic-19-10-23.log". To see more details about the error, add `--verbose` command line option.
```

The error in the logs:

```
[15:29:23 19-10-2023] DEBUG api_client.py:95 > Delete the edit '10487428624515697734' for the package 'com.placeholder.dev'
[15:29:23 19-10-2023] DEBUG api_client.py:102 > Deleted edit 10487428624515697734 for package 'com.placeholder.dev'
[15:29:23 19-10-2023] DEBUG api_client.py:83 > Create an edit for the package 'com.placeholder.dev'
[15:29:24 19-10-2023] DEBUG api_client.py:87 > Created edit {'id': '13198323921870656191', 'expiryTimeSeconds': '1697732964'} for package 'com.placeholder.dev'
[15:29:24 19-10-2023] DEBUG api_client.py:130 > Get track 'alpha' for package 'com.placeholder.dev' using edit 13198323921870656191
[15:29:24 19-10-2023] DEBUG api_client.py:138 > Got track 'alpha' for package 'com.placeholder.dev': {'track': 'alpha', 'releases': [{'name': '0.1.36', 'versionCodes': ['359'], 'releaseNotes': [{'language': 'en-US', 'text': '* Release notes\n\nwith some new lines'}], 'status': 'completed'}]}
[15:29:24 19-10-2023] DEBUG api_client.py:95 > Delete the edit '13198323921870656191' for the package 'com.placeholder.dev'
[15:29:25 19-10-2023] DEBUG api_client.py:102 > Deleted edit 13198323921870656191 for package 'com.placeholder.dev'
[15:29:25 19-10-2023] WARNING cli_app.py:114 > [31mExecuting GooglePlay action tracks failed unexpectedly. Detailed logs are available at "/var/folders/cd/l74ls6v54ds9k99wjsrs6hlc0000gn/T/codemagic-19-10-23.log". To see more details about the error, add `--verbose` command line option.[0m
[15:29:25 19-10-2023] ERROR cli_app.py:116 > Exception traceback:
Traceback (most recent call last):
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/cli/cli_app.py", line 206, in invoke_cli
    CliApp._running_app._invoke_action(args)
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/cli/cli_app.py", line 163, in _invoke_action
    return cli_action(**action_args)
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/cli/cli_app.py", line 458, in wrapper
    return func(self, *args, **kwargs)
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/tools/google_play/action_groups/tracks_action_group.py", line 124, in promote_release
    release_to_promote = dataclasses.replace(
  File "/Applications/Xcode-15.0.1.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/dataclasses.py", line 1284, in replace
    return obj.__class__(**changes)
  File "<string>", line 10, in __init__
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/google_play/resources/track.py", line 57, in __post_init__
    self.releaseNotes = [LocalizedText(**note) for note in self.releaseNotes]
  File "/Users/chriswickens/Library/Python/3.9/lib/python/site-packages/codemagic/google_play/resources/track.py", line 57, in <listcomp>
    self.releaseNotes = [LocalizedText(**note) for note in self.releaseNotes]
TypeError: codemagic.google_play.resources.track.LocalizedText() argument after ** must be a mapping, not LocalizedText
[15:29:25 19-10-2023] DEBUG cli_app.py:248 > [35m-------------------------------------------------------[0m
[15:29:25 19-10-2023] DEBUG cli_app.py:249 > [35mCompleted GooglePlay tracks in 00:03 with status code 9[0m
[15:29:25 19-10-2023] DEBUG cli_app.py:250 > [35m-------------------------------------------------------[0m
```

Not sure if there's anything unexpected about my release notes. They're pulled from `release_notes.json` in this format:

```
[
    {
        "language": "en-US",
        "text": "* Release notes\n\nwith some new lines"
    }
]
```


Discussion / hints:
@chris-wickens thanks for the report. I'll look into it and let you know when the fix is live.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81d6f047..65b16573 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+Version 0.46.1
+-------------
+
+**Bugfixes**
+- Fix Google Play release promotion with action `google-play tracks promote-release` for releases that have release notes. [PR #361](https://github.com/codemagic-ci-cd/cli-tools/pull/361)
+
 Version 0.46.0
 -------------
 
diff --git a/pyproject.toml b/pyproject.toml
index 057ab487..2d72afe9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "codemagic-cli-tools"
-version = "0.46.0"
+version = "0.46.1"
 description = "CLI tools used in Codemagic builds"
 readme = "README.md"
 authors = [
diff --git a/src/codemagic/__version__.py b/src/codemagic/__version__.py
index ea7cf142..7af43805 100644
--- a/src/codemagic/__version__.py
+++ b/src/codemagic/__version__.py
@@ -1,5 +1,5 @@
 __title__ = "codemagic-cli-tools"
 __description__ = "CLI tools used in Codemagic builds"
-__version__ = "0.46.0.dev"
+__version__ = "0.46.1.dev"
 __url__ = "https://github.com/codemagic-ci-cd/cli-tools"
 __licence__ = "GNU General Public License v3.0"
diff --git a/src/codemagic/google_play/resources/track.py b/src/codemagic/google_play/resources/track.py
index f274e9d3..179e2d18 100644
--- a/src/codemagic/google_play/resources/track.py
+++ b/src/codemagic/google_play/resources/track.py
@@ -54,7 +54,9 @@ class Release(Resource):
 
     def __post_init__(self):
         if isinstance(self.releaseNotes, list):
-            self.releaseNotes = [LocalizedText(**note) for note in self.releaseNotes]
+            self.releaseNotes = [
+                note if isinstance(note, LocalizedText) else LocalizedText(**note) for note in self.releaseNotes
+            ]
         if isinstance(self.status, str):
             self.status = ReleaseStatus(self.status)
         if isinstance(self.countryTargeting, dict):


Test patch:
diff --git a/tests/google_play/resources/test_track_resource.py b/tests/google_play/resources/test_track_resource.py
index 99d942fb..93c1e194 100644
--- a/tests/google_play/resources/test_track_resource.py
+++ b/tests/google_play/resources/test_track_resource.py
@@ -1,7 +1,13 @@
 from __future__ import annotations
 
+import dataclasses
+
 import pytest
+from codemagic.google_play.resources import Release
+from codemagic.google_play.resources import ReleaseStatus
 from codemagic.google_play.resources import Track
+from codemagic.google_play.resources.track import CountryTargeting
+from codemagic.google_play.resources.track import LocalizedText
 
 
 def test_track_initialization(api_track):
@@ -29,3 +35,32 @@ def test_max_version_code_error_no_version_codes(api_track):
     with pytest.raises(ValueError) as e:
         track.get_max_version_code()
     assert str(e.value) == 'Failed to get version code from "internal" track: releases with version code do not exist'
+
+
+def test_release():
+    release = Release(
+        **{
+            "name": "1.2.3",
+            "versionCodes": ["123"],
+            "releaseNotes": [{"language": "en-US", "text": "* Release\n\nnotes"}],
+            "status": "draft",
+        },
+    )
+
+    assert release.name == "1.2.3"
+    assert release.versionCodes == ["123"]
+    assert release.releaseNotes == [LocalizedText(language="en-US", text="* Release\n\nnotes")]
+    assert release.status is ReleaseStatus.DRAFT
+    assert release.countryTargeting is None
+
+    updated_release = dataclasses.replace(
+        release,
+        status=ReleaseStatus.COMPLETED,
+        countryTargeting={"countries": ["EE", "GB"], "includeRestOfWorld": False},  # type: ignore
+    )
+
+    assert updated_release.name == release.name
+    assert updated_release.versionCodes == release.versionCodes
+    assert updated_release.releaseNotes == release.releaseNotes
+    assert updated_release.status is ReleaseStatus.COMPLETED
+    assert updated_release.countryTargeting == CountryTargeting(countries=["EE", "GB"], includeRestOfWorld=False)