Skip to content

Commit eb59b65

Browse files
authored
Feature: Submit apps to App Store review (codemagic-ci-cd#164)
* Extract app store version submission actions into separate action group * Add action to create new app store version * Support App Store version parameters from submit to review action * Include app store review submission as publishing subaction * Add more options to ASC publishing * Fix tests * Add test for App Store submit from publish action * Reuse arguments from subactions to publish action * Fix TestFlight and App Store options * Use custom argument groups in docs * Adjust custom argument groups descriptions in docs * Bump version * Accept build filters in 'app-store-connect apps builds' * Define missing attribute * Accept strings for build version number argument * Log processing message only in case build is still being processed * Allow using multiple values for single filter * Add action to get build's app store version * Add API client method and CLI action to modify App Store version * Use existing app store version for submission if possible * Make platform optional for 'app-store-connect publish' action * Update docs * Format logs * Rename CliActionParserBuilder to ArgumentParserBuilder * Remove pretty_value method from ResourceEnum * Add test and docstring for Argument.with_custom_argument_group * Reformat publish_action * Make AppStoreVersions.read_build return type optional * Update docstring for 'create_app_store_version' * Add changelog * Update test * Fix error message when using --exclude and --not-exclude together * Rename CommonArgumentTypes.iso_8601_date to CommonArgumentTypes.iso_8601_datetime * Update descriptions for --expired and --not-expired flags * Fix updating existing app store version * Fix type hint * Fix tests * Rename tests/cli/test_argument.py -> tests/cli/argument/test_argument.py * Make ISO 8601 timestamp parsing more relaxed and add tests * Fix setting earliest release date for App Store version * Add more validation steps to earliest release date * Fix merge conflict in changelog
1 parent 95f66fd commit eb59b65

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2221
-291
lines changed

CHANGELOG.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,70 @@
1+
Version 0.13.0
2+
-------------
3+
4+
Additions and changes from [pull request #164](https://github.com/codemagic-ci-cd/cli-tools/pull/164).
5+
6+
**Features**
7+
8+
- Add new App Store Connect API client method `AppStoreVersions.create` to create an App Store version. See official API method [documentation](https://developer.apple.com/documentation/appstoreconnectapi/create_an_app_store_version).
9+
- Add new App Store Connect API client method `AppStoreVersions.read_build` to read associated build from an App Store version. See official API method [documentation](https://developer.apple.com/documentation/appstoreconnectapi/read_the_build_information_of_an_app_store_version).
10+
- Add new App Store Connect API client method `AppStoreVersions.read_app_store_version_submission` to read associated App Store version submission from an App Store version. See official API method [documentation](https://developer.apple.com/documentation/appstoreconnectapi/read_the_app_store_version_submission_information_of_an_app_store_version).
11+
- Add new App Store Connect API client method `AppStoreVersions.modify` to edit existing App Store version details. See official API method [documentation](https://developer.apple.com/documentation/appstoreconnectapi/modify_an_app_store_version).
12+
- Add new App Store Connect API client method `AppStoreVersions.delete` to delete an App Store version. See official API method [documentation](https://developer.apple.com/documentation/appstoreconnectapi/delete_an_app_store_version).
13+
- Add ability to group optional CLI action arguments into named argument groups.
14+
- Add new actions group `app-store-versions` to `app-store-connect`.
15+
- Add new action `app-store-connect app-store-versions create` to create a new App Store version using specified build to an app.
16+
- Add new action `app-store-connect app-store-versions modify` to update existing App Store version details.
17+
- Add new action `app-store-connect app-store-versions delete` to remove App Store version.
18+
- Add option to specify build filters for action `app-store-connect apps builds`.
19+
- Add new action `app-store-connect builds app-store-version` to get the App Store version of a specific build.
20+
- Add new action `app-store-connect builds submit-to-app-store` to submit specified build to App Store review. Optionally specify version details and release type.
21+
- Update `app-store-connect publish` action to allow automatic App Store review submission after binary upload.
22+
- Use grouped CLI arguments in action `app-store-connect publish` for better help messages and documentation.
23+
- Add new option `--skip-package-upload` to `app-store-connect publish`.
24+
- Add short aliases for CLI flags:
25+
- `-su` for `--skip-package-upload`,
26+
- `-sv` for `--skip-package-validation`,
27+
- `-w` for `--max-build-processing-wait`.
28+
-
29+
30+
**Fixes**
31+
32+
- Fix creating `Resource` objects that do not have any attributes.
33+
- Fix `--max-build-processing-wait` CLI option validation.
34+
- Allow non-integer version numbers for `--build-version-number`.
35+
36+
**Docs**
37+
38+
- Update docs for tool `app-store-connect`.
39+
- Create docs for `app-store-connect` actions group `app-store-versions`.
40+
- Create docs for action `app-store-connect app-store-versions create`.
41+
- Create docs for action `app-store-connect app-store-versions delete`.
42+
- Create docs for action `app-store-connect app-store-versions modify`.
43+
- Create docs for `app-store-connect` actions group `apps`.
44+
- Update docs for action `app-store-connect apps app-store-versions`.
45+
- Update docs for action `app-store-connect apps builds`.
46+
- Update docs for action `app-store-connect apps list`.
47+
- Create docs for `app-store-connect` actions group `builds`.
48+
- Create docs for action `app-store-connect builds app-store-version`.
49+
- Create docs for action `app-store-connect builds submit-to-app-store`.
50+
- Update docs for action `app-store-connect builds submit-to-testflight`.
51+
- Update docs for action `app-store-connect list-builds`.
52+
- Update docs for action `app-store-connect publish`.
53+
54+
**Development**
55+
56+
- Support filtering by multiple values for one parameter in `ResourceManager.filter`.
57+
- Change `ResourceManager._get_update_payload` to accept `relationships` in addition to `attributes`. Make `attributes` and `relationships` arguments keyword-only.
58+
- Add missing return type hints to resource manger methods that did not have them.
59+
- Extract argument parser setup from `CliApp` class into separate module under `ArgumentParserBuilder` class.
60+
- Move `create_app_store_version_submission` and `delete_app_store_version_submission` methods from `AppStoreConnect` class to `AppStoreVersionSubmissionsActionGroup`.
61+
- Collect `app-store-connect` actions arguments that are used number of times under argument groups to reduce duplication.
62+
- Refactor `PublishAction` class:
63+
- extract `publish` action arguments validation into separate method,
64+
- move decorator arguments into separate tuple,
65+
- add dataclasses for subaction options,
66+
- support App Store review submission.
67+
168
Version 0.12.1
269
-------------
370

doc.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
from __future__ import annotations
44

55
import argparse
6+
import operator
67
import os
78
import re
89
import sys
10+
from collections import defaultdict
11+
from functools import reduce
912
from pathlib import Path
1013
from typing import Callable
14+
from typing import Dict
1115
from typing import Iterable
1216
from typing import List
1317
from typing import NamedTuple
@@ -28,6 +32,7 @@ class SerializedArgument(NamedTuple):
2832
flags: str
2933
name: str
3034
required: bool
35+
argument_group_name: Optional[str]
3136
default: str
3237
nargs: bool
3338
choices: str
@@ -40,6 +45,7 @@ class Action(NamedTuple):
4045
description: str
4146
required_args: List[SerializedArgument]
4247
optional_args: List[SerializedArgument]
48+
custom_args: Dict[str, List[SerializedArgument]]
4349

4450

4551
class ActionGroup(NamedTuple):
@@ -61,6 +67,7 @@ def __init__(self, raw_arguments):
6167
self.raw_arguments = raw_arguments
6268
self.required_args: List[SerializedArgument] = []
6369
self.optional_args: List[SerializedArgument] = []
70+
self.custom_args: Dict[str, List[SerializedArgument]] = defaultdict(list)
6471

6572
@classmethod
6673
def _replace_quotes(cls, description: str) -> str:
@@ -91,16 +98,21 @@ def _serialize_argument(self, arg) -> SerializedArgument:
9198
flags=', '.join(getattr(arg._value_, 'flags', '')),
9299
name='' if arg_type and arg_type.__name__ == 'bool' else arg._name_,
93100
required=kwargs.required,
101+
argument_group_name=arg._value_.argument_group_name,
94102
default=kwargs.default,
95103
nargs=kwargs.nargs,
96104
choices=kwargs.choices,
97105
store_boolean=kwargs.store_boolean,
98106
)
99107

100108
def serialize(self) -> ArgumentsSerializer:
101-
args = list(map(self._serialize_argument, self.raw_arguments))
102-
self.required_args = [arg for arg in args if arg.required]
103-
self.optional_args = [arg for arg in args if not arg.required]
109+
for argument in map(self._serialize_argument, self.raw_arguments):
110+
if argument.required:
111+
self.required_args.append(argument)
112+
elif argument.argument_group_name:
113+
self.custom_args[argument.argument_group_name].append(argument)
114+
else:
115+
self.optional_args.append(argument)
104116
return self
105117

106118
@classmethod
@@ -165,7 +177,7 @@ def generate(self):
165177
self._write_action_group_page(group)
166178

167179
def _write_tool_command_arguments_and_options(self, writer):
168-
writer.write_arguments(f'command `{self.tool_command}`', self.tool_optional_args, self.tool_required_args)
180+
writer.write_arguments(f'command `{self.tool_command}`', self.tool_optional_args, self.tool_required_args, {})
169181
writer.write_options(self.tool_options)
170182

171183
def _write_tool_page(self):
@@ -198,7 +210,12 @@ def _write_action_page(self, action: Action, action_group: Optional[ActionGroup]
198210
writer = Writer(md)
199211
writer.write_description(action.description)
200212
writer.write_command_usage(self, action_group=action_group, action=action)
201-
writer.write_arguments(f'action `{action.action_name}`', action.optional_args, action.required_args)
213+
writer.write_arguments(
214+
f'action `{action.action_name}`',
215+
action.optional_args,
216+
action.required_args,
217+
action.custom_args,
218+
)
202219
self._write_tool_command_arguments_and_options(writer)
203220
md.create_md_file()
204221

@@ -223,6 +240,7 @@ def _serialize_action(action: Callable) -> Action:
223240
description=action.__doc__,
224241
required_args=action_args_serializer.required_args,
225242
optional_args=action_args_serializer.optional_args,
243+
custom_args=action_args_serializer.custom_args,
226244
)
227245

228246
return list(map(_serialize_action, tool.iter_class_cli_actions(action_group=action_group)))
@@ -236,6 +254,7 @@ def _serialize_option(option) -> SerializedArgument:
236254
flags=', '.join(option.option_strings),
237255
name='',
238256
required=False,
257+
argument_group_name=None,
239258
default='',
240259
nargs=False,
241260
choices=' | '.join(option.choices) if option.choices else '',
@@ -246,7 +265,7 @@ def _serialize_option(option) -> SerializedArgument:
246265
description=tool.__doc__,
247266
formatter_class=cli.cli_help_formatter.CliHelpFormatter,
248267
)
249-
tool.set_default_cli_options(parser)
268+
cli.argument.ArgumentParserBuilder.set_default_cli_options(parser)
250269
return list(map(_serialize_option, parser._actions))
251270

252271

@@ -263,6 +282,7 @@ def get_command_usage(self,
263282
action_args = [
264283
*map(self._get_formatted_flag, action.optional_args),
265284
*map(self._get_formatted_flag, action.required_args),
285+
*map(self._get_formatted_flag, reduce(operator.add, action.custom_args.values(), [])),
266286
] if action else ['ACTION']
267287

268288
return [
@@ -350,9 +370,17 @@ def _get_group_doc(group: ActionGroup) -> List[str]:
350370
self.file.new_header(level=3, title='Action groups', add_table_of_contents='n')
351371
self.write_table(list(map(_get_group_doc, groups)), ['Action group', 'Description'])
352372

353-
def write_arguments(self, obj: str, optional: List[SerializedArgument], required: List[SerializedArgument]):
373+
def write_arguments(
374+
self,
375+
obj: str,
376+
optional: List[SerializedArgument],
377+
required: List[SerializedArgument],
378+
custom: Dict[str, List[SerializedArgument]],
379+
):
354380
self._write_arguments(self.file, f'Required arguments for {obj}', required)
355381
self._write_arguments(self.file, f'Optional arguments for {obj}', optional)
382+
for group_name, custom_arguments in custom.items():
383+
self._write_arguments(self.file, f'Optional arguments to {group_name}', custom_arguments)
356384

357385
def write_options(self, options: List[SerializedArgument]):
358386
self._write_arguments(self.file, 'Common options', options)

docs/app-store-connect/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Enable verbose logging for commands
102102
|Action group|Description|
103103
| :--- | :--- |
104104
|[`app-store-version-submissions`](app-store-version-submissions.md)|Manage your application's App Store version review process|
105+
|[`app-store-versions`](app-store-versions.md)|Manage the information related to an App Store version of your app|
105106
|[`apps`](apps.md)|Manage your apps in App Store Connect|
106107
|[`beta-app-review-submissions`](beta-app-review-submissions.md)|Manage your application's TestFlight submissions|
107108
|[`beta-build-localizations`](beta-build-localizations.md)|Manage your beta builds localizations in App Store Connect|
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
2+
app-store-versions
3+
==================
4+
5+
6+
**Manage the information related to an App Store version of your app**
7+
### Usage
8+
```bash
9+
app-store-connect app-store-versions [-h] [--log-stream STREAM] [--no-color] [--version] [-s] [-v]
10+
[--log-api-calls]
11+
[--json]
12+
[--issuer-id ISSUER_ID]
13+
[--key-id KEY_IDENTIFIER]
14+
[--private-key PRIVATE_KEY]
15+
[--certificates-dir CERTIFICATES_DIRECTORY]
16+
[--profiles-dir PROFILES_DIRECTORY]
17+
ACTION
18+
```
19+
### Optional arguments for command `app-store-connect`
20+
21+
##### `--log-api-calls`
22+
23+
24+
Turn on logging for App Store Connect API HTTP requests
25+
##### `--json`
26+
27+
28+
Whether to show the resource in JSON format
29+
##### `--issuer-id=ISSUER_ID`
30+
31+
32+
App Store Connect API Key Issuer ID. Identifies the issuer who created the authentication token. Learn more at https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api. If not given, the value will be checked from the environment variable `APP_STORE_CONNECT_ISSUER_ID`. Alternatively to entering `ISSUER_ID` in plaintext, it may also be specified using the `@env:` prefix followed by an environment variable name, or the `@file:` prefix followed by a path to the file containing the value. Example: `@env:<variable>` uses the value in the environment variable named `<variable>`, and `@file:<file_path>` uses the value from the file at `<file_path>`.
33+
##### `--key-id=KEY_IDENTIFIER`
34+
35+
36+
App Store Connect API Key ID. Learn more at https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api. If not given, the value will be checked from the environment variable `APP_STORE_CONNECT_KEY_IDENTIFIER`. Alternatively to entering `KEY_IDENTIFIER` in plaintext, it may also be specified using the `@env:` prefix followed by an environment variable name, or the `@file:` prefix followed by a path to the file containing the value. Example: `@env:<variable>` uses the value in the environment variable named `<variable>`, and `@file:<file_path>` uses the value from the file at `<file_path>`.
37+
##### `--private-key=PRIVATE_KEY`
38+
39+
40+
App Store Connect API private key used for JWT authentication to communicate with Apple services. Learn more at https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api. If not provided, the key will be searched from the following directories in sequence for a private key file with the name `AuthKey_<key_identifier>.p8`: private_keys, ~/private_keys, ~/.private_keys, ~/.appstoreconnect/private_keys, where <key_identifier> is the value of --key-id. If not given, the value will be checked from the environment variable `APP_STORE_CONNECT_PRIVATE_KEY`. Alternatively to entering `PRIVATE_KEY` in plaintext, it may also be specified using the `@env:` prefix followed by an environment variable name, or the `@file:` prefix followed by a path to the file containing the value. Example: `@env:<variable>` uses the value in the environment variable named `<variable>`, and `@file:<file_path>` uses the value from the file at `<file_path>`.
41+
##### `--certificates-dir=CERTIFICATES_DIRECTORY`
42+
43+
44+
Directory where the code signing certificates will be saved. Default:&nbsp;`$HOME/Library/MobileDevice/Certificates`
45+
##### `--profiles-dir=PROFILES_DIRECTORY`
46+
47+
48+
Directory where the provisioning profiles will be saved. Default:&nbsp;`$HOME/Library/MobileDevice/Provisioning Profiles`
49+
### Common options
50+
51+
##### `-h, --help`
52+
53+
54+
show this help message and exit
55+
##### `--log-stream=stderr | stdout`
56+
57+
58+
Log output stream. Default `stderr`
59+
##### `--no-color`
60+
61+
62+
Do not use ANSI colors to format terminal output
63+
##### `--version`
64+
65+
66+
Show tool version and exit
67+
##### `-s, --silent`
68+
69+
70+
Disable log output for commands
71+
##### `-v, --verbose`
72+
73+
74+
Enable verbose logging for commands
75+
### Actions
76+
77+
|Action|Description|
78+
| :--- | :--- |
79+
|[`create`](app-store-versions/create.md)|Add a new App Store version to an app using specified build.|
80+
|[`delete`](app-store-versions/delete.md)|Delete specified App Store version from Apple Developer portal|
81+
|[`modify`](app-store-versions/modify.md)|Update the app store version for a specific app.|

0 commit comments

Comments
 (0)