Bump dev dependencies
This commit is contained in:
Родитель
2a121994fd
Коммит
ba8411986e
|
@ -1,42 +1,39 @@
|
|||
|
||||
jobs:
|
||||
- job: "Test"
|
||||
pool:
|
||||
vmImage: "ubuntu-latest"
|
||||
strategy:
|
||||
matrix:
|
||||
Python39:
|
||||
python.version: "3.9"
|
||||
Python310:
|
||||
python.version: "3.10"
|
||||
Python311:
|
||||
python.version: "3.11"
|
||||
Python312:
|
||||
python.version: "3.12"
|
||||
maxParallel: 4
|
||||
|
||||
- job: 'Test'
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
strategy:
|
||||
matrix:
|
||||
Python38:
|
||||
python.version: '3.8'
|
||||
Python39:
|
||||
python.version: '3.9'
|
||||
Python310:
|
||||
python.version: '3.10'
|
||||
Python311:
|
||||
python.version: '3.11'
|
||||
maxParallel: 4
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: "$(python.version)"
|
||||
architecture: "x64"
|
||||
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
inputs:
|
||||
versionSpec: '$(python.version)'
|
||||
architecture: 'x64'
|
||||
- script: curl -sSL https://install.python-poetry.org | python3
|
||||
displayName: Install Poetry
|
||||
|
||||
- script: curl -sSL https://install.python-poetry.org | python3
|
||||
displayName: Install Poetry
|
||||
- script: |
|
||||
poetry install
|
||||
displayName: "Install dependencies"
|
||||
|
||||
- script: |
|
||||
poetry install
|
||||
displayName: 'Install dependencies'
|
||||
- script: poetry run black --line-length 100 --check appcenter tests
|
||||
displayName: "Run Black"
|
||||
|
||||
- script:
|
||||
poetry run black --check appcenter tests
|
||||
displayName: 'Run Black'
|
||||
- script: |
|
||||
poetry run pylint --rcfile=pylintrc appcenter tests
|
||||
displayName: "Lint"
|
||||
|
||||
- script: |
|
||||
poetry run pylint --rcfile=pylintrc appcenter tests
|
||||
displayName: 'Lint'
|
||||
|
||||
- script: |
|
||||
poetry run mypy --ignore-missing-imports appcenter/ tests/
|
||||
displayName: 'Type Check'
|
||||
- script: |
|
||||
poetry run mypy --ignore-missing-imports appcenter/ tests/
|
||||
displayName: "Type Check"
|
||||
|
|
|
@ -10,4 +10,8 @@
|
|||
"--line-length",
|
||||
"100"
|
||||
],
|
||||
"black-formatter.args": [
|
||||
"--line-length",
|
||||
"100"
|
||||
],
|
||||
}
|
|
@ -5,13 +5,7 @@
|
|||
|
||||
"""App Center API wrapper."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from appcenter.account import AppCenterAccountClient
|
||||
from appcenter.analytics import AppCenterAnalyticsClient
|
||||
|
@ -35,9 +29,7 @@ class AppCenterClient:
|
|||
tokens: AppCenterTokensClient
|
||||
versions: AppCenterVersionsClient
|
||||
|
||||
def __init__(
|
||||
self, *, access_token: str, parent_logger: Optional[logging.Logger] = None
|
||||
) -> None:
|
||||
def __init__(self, *, access_token: str, parent_logger: logging.Logger | None = None) -> None:
|
||||
"""Initialize the AppCenterClient with the application id and the token."""
|
||||
|
||||
if parent_logger is None:
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# Licensed under the MIT license.
|
||||
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
import urllib.parse
|
||||
|
||||
import deserialize
|
||||
|
@ -23,7 +22,7 @@ class AppCenterAccountClient(AppCenterDerivedClient):
|
|||
def __init__(self, token: str, parent_logger: logging.Logger) -> None:
|
||||
super().__init__("account", token, parent_logger)
|
||||
|
||||
def users(self, *, owner_name: str, app_name: str) -> List[User]:
|
||||
def users(self, *, owner_name: str, app_name: str) -> list[User]:
|
||||
"""Get the users for an app
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -39,7 +38,7 @@ class AppCenterAccountClient(AppCenterDerivedClient):
|
|||
|
||||
response = self.get(request_url)
|
||||
|
||||
return deserialize.deserialize(List[User], response.json())
|
||||
return deserialize.deserialize(list[User], response.json())
|
||||
|
||||
def add_collaborator(
|
||||
self,
|
||||
|
@ -47,7 +46,7 @@ class AppCenterAccountClient(AppCenterDerivedClient):
|
|||
owner_name: str,
|
||||
app_name: str,
|
||||
user_email: str,
|
||||
role: Optional[Role] = None,
|
||||
role: Role | None = None,
|
||||
) -> None:
|
||||
"""Add a user as a collaborator to an app.
|
||||
|
||||
|
@ -57,14 +56,12 @@ class AppCenterAccountClient(AppCenterDerivedClient):
|
|||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param str user_email: The email of the user
|
||||
:param Optional[Role] role: The role the user should have (this is required for new users)
|
||||
:param Role | None role: The role the user should have (this is required for new users)
|
||||
|
||||
:returns: The list of users
|
||||
"""
|
||||
|
||||
self.log.info(
|
||||
f"Adding user {user_email} as collaborator on: {owner_name}/{app_name}"
|
||||
)
|
||||
self.log.info(f"Adding user {user_email} as collaborator on: {owner_name}/{app_name}")
|
||||
|
||||
request_url = self.generate_url(owner_name=owner_name, app_name=app_name)
|
||||
request_url += "/invitations"
|
||||
|
@ -76,9 +73,7 @@ class AppCenterAccountClient(AppCenterDerivedClient):
|
|||
|
||||
self.post(request_url, data=data)
|
||||
|
||||
def delete_collaborator(
|
||||
self, *, owner_name: str, app_name: str, user_email: str
|
||||
) -> None:
|
||||
def delete_collaborator(self, *, owner_name: str, app_name: str, user_email: str) -> None:
|
||||
"""Remove a user as a collaborator from an app.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# Licensed under the MIT license.
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
import deserialize
|
||||
|
||||
|
@ -27,13 +26,13 @@ class AppCenterAnalyticsClient(AppCenterDerivedClient):
|
|||
*,
|
||||
owner_name: str,
|
||||
app_name: str,
|
||||
releases: List[ReleaseWithDistributionGroup],
|
||||
releases: list[ReleaseWithDistributionGroup],
|
||||
) -> ReleaseCounts:
|
||||
"""Get the release counts for an app
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param List[ReleaseWithDistributionGroup] releases: The list of releases to get the counts for
|
||||
:param list[ReleaseWithDistributionGroup] releases: The list of releases to get the counts for
|
||||
|
||||
:returns: The release counts
|
||||
"""
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import datetime
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Dict, Iterator, Optional
|
||||
from typing import Any, Iterator
|
||||
import urllib.parse
|
||||
|
||||
from azure.storage.blob import BlockBlobService
|
||||
|
@ -39,9 +39,7 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
def __init__(self, token: str, parent_logger: logging.Logger) -> None:
|
||||
super().__init__("crashes", token, parent_logger)
|
||||
|
||||
def group_details(
|
||||
self, *, owner_name: str, app_name: str, error_group_id: str
|
||||
) -> ErrorGroup:
|
||||
def group_details(self, *, owner_name: str, app_name: str, error_group_id: str) -> ErrorGroup:
|
||||
"""Get the error group details.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -95,13 +93,11 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
"""
|
||||
|
||||
request_url = self.generate_url(owner_name=owner_name, app_name=app_name)
|
||||
request_url += (
|
||||
f"/errors/errorGroups/{error_group_id}/errors/{error_id}/download"
|
||||
)
|
||||
request_url += f"/errors/errorGroups/{error_group_id}/errors/{error_id}/download"
|
||||
|
||||
response = self.get(request_url)
|
||||
|
||||
return deserialize.deserialize(Dict[str, Any], response.json())
|
||||
return deserialize.deserialize(dict[str, Any], response.json())
|
||||
|
||||
def set_annotation(
|
||||
self,
|
||||
|
@ -110,7 +106,7 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
app_name: str,
|
||||
error_group_id: str,
|
||||
annotation: str,
|
||||
state: Optional[ErrorGroupState] = None,
|
||||
state: ErrorGroupState | None = None,
|
||||
) -> None:
|
||||
"""Get the error group details.
|
||||
|
||||
|
@ -118,7 +114,7 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
:param str app_name: The name of the app
|
||||
:param str error_group_id: The ID of the error group to set the annotation on
|
||||
:param str annotation: The annotation text
|
||||
:param Optional[ErrorGroupState] state: The state to set the error group to
|
||||
:param ErrorGroupState | None state: The state to set the error group to
|
||||
|
||||
The `state` parameter here does seem somewhat unusual, but it can't be
|
||||
helped unfortunately. The API requires that we set the state with the
|
||||
|
@ -141,18 +137,19 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
|
||||
self.patch(request_url, data={"state": state.value, "annotation": annotation})
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def get_error_groups(
|
||||
self,
|
||||
*,
|
||||
owner_name: str,
|
||||
app_name: str,
|
||||
start_time: datetime.datetime,
|
||||
end_time: Optional[datetime.datetime] = None,
|
||||
version: Optional[str] = None,
|
||||
app_build: Optional[str] = None,
|
||||
group_state: Optional[ErrorGroupState] = None,
|
||||
error_type: Optional[str] = None,
|
||||
order_by: Optional[str] = None,
|
||||
end_time: datetime.datetime | None = None,
|
||||
version: str | None = None,
|
||||
app_build: str | None = None,
|
||||
group_state: ErrorGroupState | None = None,
|
||||
error_type: str | None = None,
|
||||
order_by: str | None = None,
|
||||
limit: int = 30,
|
||||
) -> Iterator[ErrorGroupListItem]:
|
||||
"""Get the error groups for an app.
|
||||
|
@ -160,13 +157,13 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param datetime.datetime start_time: The time to start getting error groups from
|
||||
:param Optional[datetime.datetime] end_time: The end time to get error groups from
|
||||
:param Optional[str] version: The version of the app to restrict the search to (if any)
|
||||
:param Optional[str] app_build: The build to restrict the search to (if any)
|
||||
:param Optional[ErrorGroupState] group_state: Set to filter to just this group state (open, closed, ignored)
|
||||
:param Optional[str] error_type: Set to filter to specific types of error (all, unhandledError, handledError)
|
||||
:param Optional[str] order_by: The order by parameter to pass in (this will be encoded for you)
|
||||
:param Optional[str] limit: The max number of results to return per request (should not go past 100)
|
||||
:param datetime.datetime | None end_time: The end time to get error groups from
|
||||
:param str | None version: The version of the app to restrict the search to (if any)
|
||||
:param str | None app_build: The build to restrict the search to (if any)
|
||||
:param ErrorGroupState | None group_state: Set to filter to just this group state (open, closed, ignored)
|
||||
:param str | None error_type: Set to filter to specific types of error (all, unhandledError, handledError)
|
||||
:param str | None order_by: The order by parameter to pass in (this will be encoded for you)
|
||||
:param str | None limit: The max number of results to return per request (should not go past 100)
|
||||
|
||||
:returns: An iterator of ErrorGroupListItem
|
||||
"""
|
||||
|
@ -223,26 +220,28 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
# pylint: enable=too-many-arguments
|
||||
|
||||
def errors_in_group(
|
||||
self,
|
||||
*,
|
||||
owner_name: str,
|
||||
app_name: str,
|
||||
error_group_id: str,
|
||||
start_time: Optional[datetime.datetime] = None,
|
||||
end_time: Optional[datetime.datetime] = None,
|
||||
model: Optional[str] = None,
|
||||
operating_system: Optional[str] = None,
|
||||
start_time: datetime.datetime | None = None,
|
||||
end_time: datetime.datetime | None = None,
|
||||
model: str | None = None,
|
||||
operating_system: str | None = None,
|
||||
) -> Iterator[HandledError]:
|
||||
"""Get the errors in a group.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param str error_group_id: The ID of the group to get the errors from
|
||||
:param Optional[datetime.datetime] start_time: The time to start getting error groups from
|
||||
:param Optional[datetime.datetime] end_time: The end time to get error groups from
|
||||
:param Optional[str] model: The device model to restrict the search to (if any)
|
||||
:param Optional[str] operating_system: The OS to restrict the search to (if any)
|
||||
:param datetime.datetime | None start_time: The time to start getting error groups from
|
||||
:param datetime.datetime | None end_time: The end time to get error groups from
|
||||
:param str | None model: The device model to restrict the search to (if any)
|
||||
:param str | None operating_system: The OS to restrict the search to (if any)
|
||||
|
||||
:returns: An iterator of HandledError
|
||||
"""
|
||||
|
@ -250,7 +249,7 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
request_url = self.generate_url(owner_name=owner_name, app_name=app_name)
|
||||
request_url += f"/errors/errorGroups/{error_group_id}/errors?"
|
||||
|
||||
parameters: Dict[str, str] = {}
|
||||
parameters: dict[str, str] = {}
|
||||
|
||||
if start_time:
|
||||
parameters["start"] = start_time.replace(microsecond=0).isoformat()
|
||||
|
@ -293,8 +292,8 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
app_name: str,
|
||||
symbols_name: str,
|
||||
symbol_type: SymbolType,
|
||||
build_number: Optional[str] = None,
|
||||
version: Optional[str] = None,
|
||||
build_number: str | None = None,
|
||||
version: str | None = None,
|
||||
) -> SymbolUploadBeginResponse:
|
||||
"""Upload debug symbols
|
||||
|
||||
|
@ -302,8 +301,8 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
:param str app_name: The name of the app
|
||||
:param str symbols_path: The path to the symbols
|
||||
:param str symbol_type: The type of symbols being uploaded
|
||||
:param Optional[str] build_number: The build number (required for Android)
|
||||
:param Optional[str] version: The build version (required for Android)
|
||||
:param str | None build_number: The build number (required for Android)
|
||||
:param str | None version: The build version (required for Android)
|
||||
|
||||
:raises ValueError: If the build number or version aren't specified and it's an Android upload
|
||||
|
||||
|
@ -353,17 +352,18 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
|
||||
return deserialize.deserialize(SymbolUploadEndRequest, response.json())
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def upload_symbols(
|
||||
self,
|
||||
*,
|
||||
owner_name: str,
|
||||
app_name: str,
|
||||
symbols_path: str,
|
||||
symbols_name: Optional[str] = None,
|
||||
symbols_name: str | None = None,
|
||||
symbol_type: SymbolType,
|
||||
build_number: Optional[str] = None,
|
||||
version: Optional[str] = None,
|
||||
progress_callback: Optional[ProgressCallback] = None,
|
||||
build_number: str | None = None,
|
||||
version: str | None = None,
|
||||
progress_callback: ProgressCallback | None = None,
|
||||
) -> None:
|
||||
"""Upload debug symbols
|
||||
|
||||
|
@ -372,9 +372,9 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
:param str symbols_path: The path to the symbols
|
||||
:param str symbols_name: The name to use for the symbols (defaults to file basename)
|
||||
:param str symbol_type: The type of symbols being uploaded
|
||||
:param Optional[str] build_number: The build number (required for Android)
|
||||
:param Optional[str] version: The build version (required for Android)
|
||||
:param Optional[ProgressCallback] progress_callback: The upload progress callback
|
||||
:param str | None build_number: The build number (required for Android)
|
||||
:param str | None version: The build version (required for Android)
|
||||
:param ProgressCallback | None progress_callback: The upload progress callback
|
||||
|
||||
For the upload progress callback, this is a callable where the first
|
||||
parameter is the number of bytes uploaded, and the second parameter is
|
||||
|
@ -403,9 +403,7 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
url_components = urllib.parse.urlparse(begin_upload_response.upload_url)
|
||||
path = url_components.path[1:]
|
||||
container, blob_name = path.split("/")
|
||||
connection_string = (
|
||||
f"BlobEndpoint={url_components.scheme}://{url_components.netloc};"
|
||||
)
|
||||
connection_string = f"BlobEndpoint={url_components.scheme}://{url_components.netloc};"
|
||||
connection_string += f"SharedAccessSignature={url_components.query}"
|
||||
service = BlockBlobService(connection_string=connection_string)
|
||||
service.create_blob_from_stream(
|
||||
|
@ -421,9 +419,9 @@ class AppCenterCrashesClient(AppCenterDerivedClient):
|
|||
if commit_response.status != SymbolUploadStatus.COMMITTED:
|
||||
raise Exception("Failed to upload symbols")
|
||||
|
||||
def _next_link_polished(
|
||||
self, next_link: str, owner_name: str, app_name: str
|
||||
) -> str:
|
||||
# pylint: enable=too-many-arguments
|
||||
|
||||
def _next_link_polished(self, next_link: str, owner_name: str, app_name: str) -> str:
|
||||
"""Polish nextLink string gotten from AppCenter service
|
||||
|
||||
:param str next_link: The nextLink property from a service response when items are queried in batches
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# Licensed under the MIT license.
|
||||
|
||||
import logging
|
||||
from typing import Any, BinaryIO, Callable, Dict, Optional, Tuple
|
||||
from typing import Any, BinaryIO, Callable
|
||||
|
||||
import deserialize
|
||||
import requests
|
||||
|
@ -20,7 +20,7 @@ from tenacity import (
|
|||
from appcenter.constants import API_BASE_URL
|
||||
|
||||
|
||||
ProgressCallback = Callable[[int, Optional[int]], None]
|
||||
ProgressCallback = Callable[[int, int | None], None]
|
||||
|
||||
|
||||
class AppCenterHTTPError:
|
||||
|
@ -148,9 +148,7 @@ class AppCenterDerivedClient:
|
|||
"""
|
||||
return f"{API_BASE_URL}/v{version}"
|
||||
|
||||
def generate_url(
|
||||
self, *, version: str = "0.1", owner_name: str, app_name: str
|
||||
) -> str:
|
||||
def generate_url(self, *, version: str = "0.1", owner_name: str, app_name: str) -> str:
|
||||
"""Generate a URL to use for querying the API.
|
||||
|
||||
:param str version: The API version to hit
|
||||
|
@ -206,9 +204,7 @@ class AppCenterDerivedClient:
|
|||
|
||||
:raises AppCenterHTTPException: If the request fails with a non 200 status code
|
||||
"""
|
||||
response = self.session.patch(
|
||||
url, headers={"Content-Type": "application/json"}, json=data
|
||||
)
|
||||
response = self.session.patch(url, headers={"Content-Type": "application/json"}, json=data)
|
||||
|
||||
if response.status_code < 200 or response.status_code >= 300:
|
||||
raise create_exception(response)
|
||||
|
@ -230,9 +226,7 @@ class AppCenterDerivedClient:
|
|||
|
||||
:raises AppCenterHTTPException: If the request fails with a non 200 status code
|
||||
"""
|
||||
response = self.session.post(
|
||||
url, headers={"Content-Type": "application/json"}, json=data
|
||||
)
|
||||
response = self.session.post(url, headers={"Content-Type": "application/json"}, json=data)
|
||||
|
||||
if response.status_code < 200 or response.status_code >= 300:
|
||||
raise create_exception(response)
|
||||
|
@ -266,9 +260,7 @@ class AppCenterDerivedClient:
|
|||
wait=wait_fixed(10),
|
||||
stop=stop_after_attempt(3),
|
||||
)
|
||||
def post_files(
|
||||
self, url: str, *, files: Dict[str, Tuple[str, BinaryIO]]
|
||||
) -> requests.Response:
|
||||
def post_files(self, url: str, *, files: dict[str, tuple[str, BinaryIO]]) -> requests.Response:
|
||||
"""Perform a POST request to a url, sending files
|
||||
|
||||
:param url: The URL to run the POST on
|
||||
|
@ -314,9 +306,7 @@ class AppCenterDerivedClient:
|
|||
wait=wait_fixed(10),
|
||||
stop=stop_after_attempt(3),
|
||||
)
|
||||
def azure_blob_upload(
|
||||
self, url: str, *, file_stream: BinaryIO
|
||||
) -> requests.Response:
|
||||
def azure_blob_upload(self, url: str, *, file_stream: BinaryIO) -> requests.Response:
|
||||
"""Upload a file to an Azure Blob Storage URL
|
||||
|
||||
:param url: The URL to upload to
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
import datetime
|
||||
import enum
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
import deserialize
|
||||
|
||||
|
||||
def iso8601parse(date_string: Optional[str]) -> Optional[datetime.datetime]:
|
||||
def iso8601parse(date_string: str | None) -> datetime.datetime | None:
|
||||
"""Parse an ISO8601 date string into a datetime.
|
||||
|
||||
:param date_string: The date string to parse
|
||||
|
@ -40,19 +40,19 @@ class HandledErrorReasonFrame:
|
|||
JAVA = "Java"
|
||||
UNKNOWN = "Unknown"
|
||||
|
||||
className: Optional[str] # name of the class
|
||||
method: Optional[str] # name of the method
|
||||
classMethod: Optional[bool] # is a class method
|
||||
file: Optional[str] # name of the file
|
||||
line: Optional[int] # line number
|
||||
appCode: Optional[bool] # this line isn't from any framework
|
||||
frameworkName: Optional[str] # Name of the framework
|
||||
codeFormatted: Optional[str] # Formatted frame string
|
||||
codeRaw: Optional[str] # Unformatted Frame string
|
||||
methodParams: Optional[str] # parameters of the frames method
|
||||
exceptionType: Optional[str] # Exception type.
|
||||
osExceptionType: Optional[str] # OS exception type. (aka. SIGNAL)
|
||||
language: Optional[ProgrammingLanguage] # programming language of the frame
|
||||
className: str | None # name of the class
|
||||
method: str | None # name of the method
|
||||
classMethod: bool | None # is a class method
|
||||
file: str | None # name of the file
|
||||
line: int | None # line number
|
||||
appCode: bool | None # this line isn't from any framework
|
||||
frameworkName: str | None # Name of the framework
|
||||
codeFormatted: str | None # Formatted frame string
|
||||
codeRaw: str | None # Unformatted Frame string
|
||||
methodParams: str | None # parameters of the frames method
|
||||
exceptionType: str | None # Exception type.
|
||||
osExceptionType: str | None # OS exception type. (aka. SIGNAL)
|
||||
language: ProgrammingLanguage | None # programming language of the frame
|
||||
|
||||
|
||||
class ErrorGroupState(enum.Enum):
|
||||
|
@ -65,89 +65,89 @@ class ErrorGroupState(enum.Enum):
|
|||
@deserialize.parser("lastOccurrence", iso8601parse)
|
||||
class ErrorGroupListItem:
|
||||
state: ErrorGroupState
|
||||
annotation: Optional[str]
|
||||
annotation: str | None
|
||||
errorGroupId: str
|
||||
appVersion: str
|
||||
appBuild: Optional[str]
|
||||
appBuild: str | None
|
||||
count: int
|
||||
deviceCount: int
|
||||
firstOccurrence: datetime.datetime
|
||||
lastOccurrence: datetime.datetime
|
||||
exceptionType: Optional[str]
|
||||
exceptionMessage: Optional[str]
|
||||
exceptionClassName: Optional[str]
|
||||
exceptionClassMethod: Optional[bool]
|
||||
exceptionMethod: Optional[str]
|
||||
exceptionAppCode: Optional[bool]
|
||||
exceptionFile: Optional[str]
|
||||
exceptionLine: Optional[str]
|
||||
codeRaw: Optional[str]
|
||||
reasonFrames: Optional[List[HandledErrorReasonFrame]]
|
||||
exceptionType: str | None
|
||||
exceptionMessage: str | None
|
||||
exceptionClassName: str | None
|
||||
exceptionClassMethod: bool | None
|
||||
exceptionMethod: str | None
|
||||
exceptionAppCode: bool | None
|
||||
exceptionFile: str | None
|
||||
exceptionLine: str | None
|
||||
codeRaw: str | None
|
||||
reasonFrames: list[HandledErrorReasonFrame] | None
|
||||
|
||||
|
||||
class ErrorGroups:
|
||||
nextLink: Optional[str]
|
||||
errorGroups: Optional[List[ErrorGroupListItem]]
|
||||
nextLink: str | None
|
||||
errorGroups: list[ErrorGroupListItem] | None
|
||||
|
||||
|
||||
@deserialize.parser("firstOccurrence", iso8601parse)
|
||||
@deserialize.parser("lastOccurrence", iso8601parse)
|
||||
class ErrorGroup:
|
||||
state: ErrorGroupState
|
||||
annotation: Optional[str]
|
||||
annotation: str | None
|
||||
errorGroupId: str
|
||||
appVersion: str
|
||||
appBuild: Optional[str]
|
||||
appBuild: str | None
|
||||
count: int
|
||||
deviceCount: int
|
||||
firstOccurrence: datetime.datetime
|
||||
lastOccurrence: datetime.datetime
|
||||
exceptionType: Optional[str]
|
||||
exceptionMessage: Optional[str]
|
||||
exceptionClassName: Optional[str]
|
||||
exceptionClassMethod: Optional[bool]
|
||||
exceptionMethod: Optional[str]
|
||||
exceptionAppCode: Optional[bool]
|
||||
exceptionFile: Optional[str]
|
||||
exceptionLine: Optional[str]
|
||||
codeRaw: Optional[str]
|
||||
reasonFrames: Optional[List[HandledErrorReasonFrame]]
|
||||
exceptionType: str | None
|
||||
exceptionMessage: str | None
|
||||
exceptionClassName: str | None
|
||||
exceptionClassMethod: bool | None
|
||||
exceptionMethod: str | None
|
||||
exceptionAppCode: bool | None
|
||||
exceptionFile: str | None
|
||||
exceptionLine: str | None
|
||||
codeRaw: str | None
|
||||
reasonFrames: list[HandledErrorReasonFrame] | None
|
||||
|
||||
|
||||
@deserialize.parser("timestamp", iso8601parse)
|
||||
class HandledError:
|
||||
errorId: Optional[str]
|
||||
timestamp: Optional[datetime.datetime]
|
||||
deviceName: Optional[str]
|
||||
osVersion: Optional[str]
|
||||
osType: Optional[str]
|
||||
country: Optional[str]
|
||||
language: Optional[str]
|
||||
userId: Optional[str]
|
||||
errorId: str | None
|
||||
timestamp: datetime.datetime | None
|
||||
deviceName: str | None
|
||||
osVersion: str | None
|
||||
osType: str | None
|
||||
country: str | None
|
||||
language: str | None
|
||||
userId: str | None
|
||||
|
||||
|
||||
class HandledErrors:
|
||||
nextLink: Optional[str]
|
||||
errors: Optional[List[HandledError]]
|
||||
nextLink: str | None
|
||||
errors: list[HandledError] | None
|
||||
|
||||
|
||||
@deserialize.parser("timestamp", iso8601parse)
|
||||
@deserialize.parser("appLaunchTimestamp", iso8601parse)
|
||||
class HandledErrorDetails:
|
||||
errorId: Optional[str]
|
||||
timestamp: Optional[datetime.datetime]
|
||||
deviceName: Optional[str]
|
||||
osVersion: Optional[str]
|
||||
osType: Optional[str]
|
||||
country: Optional[str]
|
||||
language: Optional[str]
|
||||
userId: Optional[str]
|
||||
name: Optional[str]
|
||||
reasonFrames: Optional[List[HandledErrorReasonFrame]]
|
||||
appLaunchTimestamp: Optional[datetime.datetime]
|
||||
carrierName: Optional[str]
|
||||
jailbreak: Optional[bool]
|
||||
properties: Optional[Dict[str, str]]
|
||||
errorId: str | None
|
||||
timestamp: datetime.datetime | None
|
||||
deviceName: str | None
|
||||
osVersion: str | None
|
||||
osType: str | None
|
||||
country: str | None
|
||||
language: str | None
|
||||
userId: str | None
|
||||
name: str | None
|
||||
reasonFrames: list[HandledErrorReasonFrame] | None
|
||||
appLaunchTimestamp: datetime.datetime | None
|
||||
carrierName: str | None
|
||||
jailbreak: bool | None
|
||||
properties: dict[str, str | None]
|
||||
|
||||
|
||||
class ReleaseOrigin(enum.Enum):
|
||||
|
@ -157,21 +157,21 @@ class ReleaseOrigin(enum.Enum):
|
|||
|
||||
@deserialize.auto_snake()
|
||||
class BuildInfo:
|
||||
branch_name: Optional[str]
|
||||
commit_hash: Optional[str]
|
||||
commit_message: Optional[str]
|
||||
branch_name: str | None
|
||||
commit_hash: str | None
|
||||
commit_message: str | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
branch_name: Optional[str] = None,
|
||||
commit_hash: Optional[str] = None,
|
||||
commit_message: Optional[str] = None,
|
||||
branch_name: str | None = None,
|
||||
commit_hash: str | None = None,
|
||||
commit_message: str | None = None,
|
||||
) -> None:
|
||||
self.branch_name = branch_name
|
||||
self.commit_hash = commit_hash
|
||||
self.commit_message = commit_message
|
||||
|
||||
def json(self) -> Dict[str, Any]:
|
||||
def json(self) -> dict[str, Any]:
|
||||
result = {}
|
||||
|
||||
if self.branch_name is not None:
|
||||
|
@ -203,12 +203,12 @@ class DestinationType(enum.Enum):
|
|||
@deserialize.key("store_type", "type")
|
||||
class Destination:
|
||||
identifier: str
|
||||
name: Optional[str]
|
||||
is_latest: Optional[bool]
|
||||
store_type: Optional[StoreType]
|
||||
publishing_status: Optional[str]
|
||||
destination_type: Optional[DestinationType]
|
||||
display_name: Optional[str]
|
||||
name: str | None
|
||||
is_latest: bool | None
|
||||
store_type: StoreType | None
|
||||
publishing_status: str | None
|
||||
destination_type: DestinationType | None
|
||||
display_name: str | None
|
||||
|
||||
|
||||
@deserialize.key("identifier", "id")
|
||||
|
@ -216,12 +216,12 @@ class Destination:
|
|||
class BasicReleaseDetailsResponse:
|
||||
identifier: int
|
||||
version: str
|
||||
origin: Optional[ReleaseOrigin]
|
||||
origin: ReleaseOrigin | None
|
||||
short_version: str
|
||||
enabled: bool
|
||||
uploaded_at: datetime.datetime
|
||||
destinations: Optional[List[Destination]]
|
||||
build: Optional[BuildInfo]
|
||||
destinations: list[Destination] | None
|
||||
build: BuildInfo | None
|
||||
|
||||
|
||||
class ProvisioningProfileType(enum.Enum):
|
||||
|
@ -244,84 +244,84 @@ class ReleaseDetailsResponse:
|
|||
app_display_name: str
|
||||
|
||||
# The app's OS.
|
||||
app_os: Optional[str]
|
||||
app_os: str | None
|
||||
|
||||
# The release's version.
|
||||
version: str
|
||||
|
||||
# The release's origin
|
||||
origin: Optional[ReleaseOrigin]
|
||||
origin: ReleaseOrigin | None
|
||||
|
||||
# The release's short version.
|
||||
short_version: str
|
||||
|
||||
# The release's release notes.
|
||||
release_notes: Optional[str]
|
||||
release_notes: str | None
|
||||
|
||||
# The release's provisioning profile name.
|
||||
provisioning_profile_name: Optional[str]
|
||||
provisioning_profile_name: str | None
|
||||
|
||||
# The type of the provisioning profile for the requested app version.
|
||||
provisioning_profile_type: Optional[ProvisioningProfileType]
|
||||
provisioning_profile_type: ProvisioningProfileType | None
|
||||
|
||||
# expiration date of provisioning profile in UTC format.
|
||||
provisioning_profile_expiry_date: Optional[datetime.datetime]
|
||||
provisioning_profile_expiry_date: datetime.datetime | None
|
||||
|
||||
# A flag that determines whether the release's provisioning profile is still extracted or not.
|
||||
is_provisioning_profile_syncing: Optional[bool]
|
||||
is_provisioning_profile_syncing: bool | None
|
||||
|
||||
# The release's size in bytes.
|
||||
size: Optional[int]
|
||||
size: int | None
|
||||
|
||||
# The release's minimum required operating system.
|
||||
min_os: Optional[str]
|
||||
min_os: str | None
|
||||
|
||||
# The release's device family.
|
||||
device_family: Optional[str]
|
||||
device_family: str | None
|
||||
|
||||
# The release's minimum required Android API level.
|
||||
android_min_api_level: Optional[str]
|
||||
android_min_api_level: str | None
|
||||
|
||||
# The identifier of the apps bundle.
|
||||
bundle_identifier: Optional[str]
|
||||
bundle_identifier: str | None
|
||||
|
||||
# Hashes for the packages
|
||||
package_hashes: Optional[List[str]]
|
||||
package_hashes: list[str | None]
|
||||
|
||||
# MD5 checksum of the release binary.
|
||||
fingerprint: Optional[str]
|
||||
fingerprint: str | None
|
||||
|
||||
# The uploaded time.
|
||||
uploaded_at: datetime.datetime
|
||||
|
||||
# The URL that hosts the binary for this release.
|
||||
download_url: Optional[str]
|
||||
download_url: str | None
|
||||
|
||||
# A URL to the app's icon.
|
||||
app_icon_url: Optional[str]
|
||||
app_icon_url: str | None
|
||||
|
||||
# The href required to install a release on a mobile device. On iOS devices will be prefixed
|
||||
# with itms-services://?action=download-manifest&url=
|
||||
install_url: Optional[str]
|
||||
install_url: str | None
|
||||
|
||||
destinations: Optional[List[Destination]]
|
||||
destinations: list[Destination] | None
|
||||
|
||||
# In calls that allow passing udid in the query string, this value will hold the provisioning
|
||||
# status of that UDID in this release. Will be ignored for non-iOS platforms.
|
||||
is_udid_provisioned: Optional[bool]
|
||||
is_udid_provisioned: bool | None
|
||||
|
||||
# In calls that allow passing udid in the query string, this value determines if a release can
|
||||
# be re-signed. When true, after a re-sign, the tester will be able to install the release from
|
||||
# his registered devices. Will not be returned for non-iOS platforms.
|
||||
can_resign: Optional[bool]
|
||||
can_resign: bool | None
|
||||
|
||||
build: Optional[BuildInfo]
|
||||
build: BuildInfo | None
|
||||
|
||||
# This value determines the whether a release currently is enabled or disabled.
|
||||
enabled: bool
|
||||
|
||||
# Status of the release.
|
||||
status: Optional[str]
|
||||
status: str | None
|
||||
|
||||
|
||||
class ReleaseWithDistributionGroup:
|
||||
|
@ -335,14 +335,14 @@ class ReleaseWithDistributionGroup:
|
|||
|
||||
class ReleaseCount:
|
||||
release_id: str
|
||||
distribution_group: Optional[str]
|
||||
distribution_group: str | None
|
||||
unique_count: int
|
||||
total_count: int
|
||||
|
||||
|
||||
class ReleaseCounts:
|
||||
total: Optional[int]
|
||||
counts: List[ReleaseCount]
|
||||
total: int | None
|
||||
counts: list[ReleaseCount]
|
||||
|
||||
|
||||
@deserialize.key("identifier", "id")
|
||||
|
@ -351,7 +351,7 @@ class SetUploadMetadataResponse:
|
|||
error: bool
|
||||
chunk_size: int
|
||||
resume_restart: bool
|
||||
chunk_list: List[int]
|
||||
chunk_list: list[int]
|
||||
blob_partitions: int
|
||||
status_code: str
|
||||
|
||||
|
@ -375,7 +375,7 @@ class CreateReleaseUploadResponse:
|
|||
class CommitUploadResponse:
|
||||
identifier: str
|
||||
upload_status: str
|
||||
release_distinct_id: Optional[int]
|
||||
release_distinct_id: int | None
|
||||
|
||||
|
||||
@deserialize.key("identifier", "id")
|
||||
|
@ -383,7 +383,7 @@ class UploadCompleteResponse:
|
|||
absolute_uri: str
|
||||
chunk_num: int
|
||||
error: bool
|
||||
error_code: Optional[str]
|
||||
error_code: str | None
|
||||
location: str
|
||||
message: str
|
||||
raw_location: str
|
||||
|
@ -394,22 +394,20 @@ class UploadCompleteResponse:
|
|||
class ReleaseDestinationResponse:
|
||||
identifier: str
|
||||
mandatory_update: bool
|
||||
provisioning_status_url: Optional[str]
|
||||
provisioning_status_url: str | None
|
||||
|
||||
|
||||
@deserialize.key("identifier", "id")
|
||||
class DestinationId:
|
||||
name: Optional[str]
|
||||
identifier: Optional[str]
|
||||
name: str | None
|
||||
identifier: str | None
|
||||
|
||||
def __init__(
|
||||
self, *, name: Optional[str] = None, identifier: Optional[str] = None
|
||||
) -> None:
|
||||
def __init__(self, *, name: str | None = None, identifier: str | None = None) -> None:
|
||||
self.name = name
|
||||
self.identifier = identifier
|
||||
|
||||
def json(self) -> Dict[str, Any]:
|
||||
result: Dict[str, Any] = {}
|
||||
def json(self) -> dict[str, Any]:
|
||||
result: dict[str, Any] = {}
|
||||
|
||||
if self.name is not None:
|
||||
result["name"] = self.name
|
||||
|
@ -421,20 +419,20 @@ class DestinationId:
|
|||
|
||||
|
||||
class ReleaseUpdateRequest:
|
||||
release_notes: Optional[str]
|
||||
mandatory_update: Optional[bool]
|
||||
destinations: Optional[List[DestinationId]]
|
||||
build: Optional[BuildInfo]
|
||||
notify_testers: Optional[bool]
|
||||
release_notes: str | None
|
||||
mandatory_update: bool | None
|
||||
destinations: list[DestinationId] | None
|
||||
build: BuildInfo | None
|
||||
notify_testers: bool | None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
release_notes: Optional[str] = None,
|
||||
mandatory_update: Optional[bool] = None,
|
||||
destinations: Optional[List[DestinationId]] = None,
|
||||
build: Optional[BuildInfo] = None,
|
||||
notify_testers: Optional[bool] = None,
|
||||
release_notes: str | None = None,
|
||||
mandatory_update: bool | None = None,
|
||||
destinations: list[DestinationId] | None = None,
|
||||
build: BuildInfo | None = None,
|
||||
notify_testers: bool | None = None,
|
||||
) -> None:
|
||||
self.release_notes = release_notes
|
||||
self.mandatory_update = mandatory_update
|
||||
|
@ -442,8 +440,8 @@ class ReleaseUpdateRequest:
|
|||
self.build = build
|
||||
self.notify_testers = notify_testers
|
||||
|
||||
def json(self) -> Dict[str, Any]:
|
||||
output: Dict[str, Any] = {}
|
||||
def json(self) -> dict[str, Any]:
|
||||
output: dict[str, Any] = {}
|
||||
|
||||
if self.release_notes is not None:
|
||||
output["release_notes"] = self.release_notes
|
||||
|
@ -452,9 +450,7 @@ class ReleaseUpdateRequest:
|
|||
output["mandatory_update"] = self.mandatory_update
|
||||
|
||||
if self.destinations is not None:
|
||||
output["destinations"] = [
|
||||
destination.json() for destination in self.destinations
|
||||
]
|
||||
output["destinations"] = [destination.json() for destination in self.destinations]
|
||||
|
||||
if self.build is not None:
|
||||
output["build"] = self.build.json()
|
||||
|
@ -514,10 +510,10 @@ class User:
|
|||
identifier: str
|
||||
|
||||
# The avatar URL of the user
|
||||
avatar_url: Optional[str]
|
||||
avatar_url: str | None
|
||||
|
||||
# User is required to send an old password in order to change the password
|
||||
can_change_password: Optional[bool]
|
||||
can_change_password: bool | None
|
||||
|
||||
# The full name of the user. Might for example be first and last name
|
||||
display_name: str
|
||||
|
@ -529,7 +525,7 @@ class User:
|
|||
name: str
|
||||
|
||||
# The permissions the user has for the app
|
||||
permissions: List[Permission]
|
||||
permissions: list[Permission]
|
||||
|
||||
# The creation origin of this user
|
||||
origin: Origin
|
||||
|
@ -545,10 +541,10 @@ class UserToken:
|
|||
description: str
|
||||
|
||||
# The scope the token has
|
||||
scope: List[str]
|
||||
scope: list[str]
|
||||
|
||||
# The creation date
|
||||
created_at: datetime.datetime
|
||||
|
||||
# The value of the token - Only set when creating a new tokern
|
||||
api_token: Optional[str]
|
||||
api_token: str | None
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
import enum
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
import deserialize
|
||||
|
||||
|
@ -29,7 +28,7 @@ class AppCenterTokensClient(AppCenterDerivedClient):
|
|||
def __init__(self, token: str, parent_logger: logging.Logger) -> None:
|
||||
super().__init__("tokens", token, parent_logger)
|
||||
|
||||
def get_user_tokens(self) -> List[UserToken]:
|
||||
def get_user_tokens(self) -> list[UserToken]:
|
||||
"""Get the users tokens
|
||||
|
||||
:returns: The tokens
|
||||
|
@ -42,7 +41,7 @@ class AppCenterTokensClient(AppCenterDerivedClient):
|
|||
|
||||
response = self.get(request_url)
|
||||
|
||||
return deserialize.deserialize(List[UserToken], response.json())
|
||||
return deserialize.deserialize(list[UserToken], response.json())
|
||||
|
||||
def create_user_token(self, name: str, scope: TokenScope) -> UserToken:
|
||||
"""Create a user token.
|
||||
|
@ -56,13 +55,11 @@ class AppCenterTokensClient(AppCenterDerivedClient):
|
|||
|
||||
self.log.debug(f"Creating user token name={name}, scope={scope}")
|
||||
|
||||
response = self.post(
|
||||
request_url, data={"description": name, "scope": [scope.value]}
|
||||
)
|
||||
response = self.post(request_url, data={"description": name, "scope": [scope.value]})
|
||||
|
||||
return deserialize.deserialize(UserToken, response.json())
|
||||
|
||||
def delete_user_token(self, token: Union[str, UserToken]) -> None:
|
||||
def delete_user_token(self, token: str | UserToken) -> None:
|
||||
"""Delete a user token.
|
||||
|
||||
:param token: The token itself or the ID for the token
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import Iterator, List, Optional
|
||||
from typing import Iterator
|
||||
import urllib.parse
|
||||
|
||||
import deserialize
|
||||
|
@ -56,9 +56,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
def __init__(self, token: str, parent_logger: logging.Logger) -> None:
|
||||
super().__init__("versions", token, parent_logger)
|
||||
|
||||
def recent(
|
||||
self, *, owner_name: str, app_name: str
|
||||
) -> List[BasicReleaseDetailsResponse]:
|
||||
def recent(self, *, owner_name: str, app_name: str) -> list[BasicReleaseDetailsResponse]:
|
||||
"""Get the recent version for each distribution group.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -74,9 +72,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
response = self.get(request_url)
|
||||
|
||||
return deserialize.deserialize(
|
||||
List[BasicReleaseDetailsResponse], response.json()
|
||||
)
|
||||
return deserialize.deserialize(list[BasicReleaseDetailsResponse], response.json())
|
||||
|
||||
def all(
|
||||
self,
|
||||
|
@ -84,14 +80,14 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
owner_name: str,
|
||||
app_name: str,
|
||||
published_only: bool = False,
|
||||
scope: Optional[str] = None,
|
||||
scope: str | None = None,
|
||||
) -> Iterator[BasicReleaseDetailsResponse]:
|
||||
"""Get all (the 100 latest) versions.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param bool published_only: Return only the published releases (defaults to false)
|
||||
:param Optional[str] scope: When the scope is 'tester', only includes
|
||||
:param str | None scope: When the scope is 'tester', only includes
|
||||
releases that have been distributed to
|
||||
groups that the user belongs to.
|
||||
|
||||
|
@ -112,9 +108,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
response = self.get(request_url)
|
||||
|
||||
return deserialize.deserialize(
|
||||
List[BasicReleaseDetailsResponse], response.json()
|
||||
)
|
||||
return deserialize.deserialize(list[BasicReleaseDetailsResponse], response.json())
|
||||
|
||||
def release_details(
|
||||
self, *, owner_name: str, app_name: str, release_id: int
|
||||
|
@ -137,9 +131,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
return deserialize.deserialize(ReleaseDetailsResponse, response.json())
|
||||
|
||||
def release_id_for_version(
|
||||
self, *, owner_name: str, app_name: str, version: str
|
||||
) -> Optional[int]:
|
||||
def release_id_for_version(self, *, owner_name: str, app_name: str, version: str) -> int | None:
|
||||
"""Get the App Center release identifier for the app version (usually build number).
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -155,7 +147,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
return None
|
||||
|
||||
def latest_commit(self, *, owner_name: str, app_name: str) -> Optional[str]:
|
||||
def latest_commit(self, *, owner_name: str, app_name: str) -> str | None:
|
||||
"""Find the most recent release which has an available commit in it and return the commit hash.
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -179,9 +171,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
return None
|
||||
|
||||
def get_upload_url(
|
||||
self, *, owner_name: str, app_name: str
|
||||
) -> CreateReleaseUploadResponse:
|
||||
def get_upload_url(self, *, owner_name: str, app_name: str) -> CreateReleaseUploadResponse:
|
||||
"""Get the App Center release identifier for the app version (usually build number).
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
|
@ -214,7 +204,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
*,
|
||||
create_release_upload_response: CreateReleaseUploadResponse,
|
||||
binary_path: str,
|
||||
) -> Optional[SetUploadMetadataResponse]:
|
||||
) -> SetUploadMetadataResponse | None:
|
||||
"""Set the metadata for a binary upload
|
||||
|
||||
:param CreateReleaseUploadResponse create_release_upload_response: The response to a `get_upload_url` call
|
||||
|
@ -230,9 +220,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
mime_type = MIME_TYPES.get(file_ext)
|
||||
|
||||
request_url = create_release_upload_response.upload_domain
|
||||
request_url += (
|
||||
f"/upload/set_metadata/{create_release_upload_response.package_asset_id}?"
|
||||
)
|
||||
request_url += f"/upload/set_metadata/{create_release_upload_response.package_asset_id}?"
|
||||
|
||||
parameters = {"file_name": file_name, "file_size": file_size}
|
||||
|
||||
|
@ -247,9 +235,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
try:
|
||||
response = self.post(request_url, data={})
|
||||
if response.ok:
|
||||
return deserialize.deserialize(
|
||||
SetUploadMetadataResponse, response.json()
|
||||
)
|
||||
return deserialize.deserialize(SetUploadMetadataResponse, response.json())
|
||||
except Exception as ex:
|
||||
if attempt < 2:
|
||||
self.log.warning(f"Failed to post in set_upload_metadata: {ex}")
|
||||
|
@ -266,7 +252,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
chunk_number: int,
|
||||
chunk: bytearray,
|
||||
create_release_upload_response: CreateReleaseUploadResponse,
|
||||
) -> Optional[SetUploadMetadataResponse]:
|
||||
) -> SetUploadMetadataResponse | None:
|
||||
"""Set the metadata for a binary upload
|
||||
|
||||
:param CreateReleaseUploadResponse create_release_upload_response: The response to a `get_upload_url` call
|
||||
|
@ -276,9 +262,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
"""
|
||||
|
||||
request_url = create_release_upload_response.upload_domain
|
||||
request_url += (
|
||||
f"/upload/upload_chunk/{create_release_upload_response.package_asset_id}?"
|
||||
)
|
||||
request_url += f"/upload/upload_chunk/{create_release_upload_response.package_asset_id}?"
|
||||
|
||||
parameters = {"block_number": chunk_number}
|
||||
|
||||
|
@ -303,7 +287,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
def _mark_upload_finished(
|
||||
self, *, create_release_upload_response: CreateReleaseUploadResponse
|
||||
) -> Optional[UploadCompleteResponse]:
|
||||
) -> UploadCompleteResponse | None:
|
||||
"""Mark the upload of a binary as finished
|
||||
|
||||
:param CreateReleaseUploadResponse create_release_upload_response: The response to a `get_upload_url` call
|
||||
|
@ -312,9 +296,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
"""
|
||||
|
||||
request_url = create_release_upload_response.upload_domain
|
||||
request_url += (
|
||||
f"/upload/finished/{create_release_upload_response.package_asset_id}?"
|
||||
)
|
||||
request_url += f"/upload/finished/{create_release_upload_response.package_asset_id}?"
|
||||
|
||||
parameters = {"callback": ""}
|
||||
|
||||
|
@ -326,9 +308,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
try:
|
||||
response = self.post_raw_data(request_url, data=None)
|
||||
if response.ok:
|
||||
return deserialize.deserialize(
|
||||
UploadCompleteResponse, response.json()
|
||||
)
|
||||
return deserialize.deserialize(UploadCompleteResponse, response.json())
|
||||
except Exception as ex:
|
||||
if attempt < 2:
|
||||
self.log.warning(f"Failed to post in _mark_upload_finished: {ex}")
|
||||
|
@ -375,9 +355,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
create_release_upload_response=create_release_upload_response,
|
||||
)
|
||||
if response is None:
|
||||
self.log.warn(
|
||||
f"Failed to get response for uploading chunk {chunk_number}"
|
||||
)
|
||||
self.log.warn(f"Failed to get response for uploading chunk {chunk_number}")
|
||||
unhandled_chunks.append((chunk_number, 0, chunk))
|
||||
except Exception as ex:
|
||||
self.log.warn(
|
||||
|
@ -397,9 +375,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
return False
|
||||
direct_upload_chunk(chunk, chunk_number)
|
||||
|
||||
self._mark_upload_finished(
|
||||
create_release_upload_response=create_release_upload_response
|
||||
)
|
||||
self._mark_upload_finished(create_release_upload_response=create_release_upload_response)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -462,9 +438,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
continue
|
||||
|
||||
try:
|
||||
response_data = deserialize.deserialize(
|
||||
CommitUploadResponse, response.json()
|
||||
)
|
||||
response_data = deserialize.deserialize(CommitUploadResponse, response.json())
|
||||
except Exception as ex:
|
||||
self.log.warning(f"Failed to get response data: {ex}")
|
||||
wait()
|
||||
|
@ -580,19 +554,19 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
app_name: str,
|
||||
binary_path: str,
|
||||
release_notes: str,
|
||||
branch_name: Optional[str] = None,
|
||||
commit_hash: Optional[str] = None,
|
||||
commit_message: Optional[str] = None,
|
||||
) -> Optional[int]:
|
||||
branch_name: str | None = None,
|
||||
commit_hash: str | None = None,
|
||||
commit_message: str | None = None,
|
||||
) -> int | None:
|
||||
"""Get the App Center release identifier for the app version (usually build number).
|
||||
|
||||
:param str owner_name: The name of the app account owner
|
||||
:param str app_name: The name of the app
|
||||
:param str binary_path: The path to the binary to upload
|
||||
:param str release_notes: The release notes for the release
|
||||
:param Optional[str] branch_name: The git branch that the build came from
|
||||
:param Optional[str] commit_hash: The hash of the commit that was just built
|
||||
:param Optional[str] commit_message: The message of the commit that was just built
|
||||
:param str | None branch_name: The git branch that the build came from
|
||||
:param str | None commit_hash: The hash of the commit that was just built
|
||||
:param str | None commit_message: The message of the commit that was just built
|
||||
|
||||
:raises FileNotFoundError: If the supplied binary is not found
|
||||
:raises Exception: If we don't get a release ID back after upload
|
||||
|
@ -635,9 +609,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
commit_hash=commit_hash,
|
||||
commit_message=commit_message,
|
||||
)
|
||||
update_request = ReleaseUpdateRequest(
|
||||
release_notes=release_notes, build=build_info
|
||||
)
|
||||
update_request = ReleaseUpdateRequest(release_notes=release_notes, build=build_info)
|
||||
|
||||
self.update_release(
|
||||
owner_name=owner_name,
|
||||
|
@ -648,6 +620,7 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
|
||||
return upload_end_response.release_distinct_id
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
def upload_and_release(
|
||||
self,
|
||||
*,
|
||||
|
@ -656,10 +629,10 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
binary_path: str,
|
||||
group_id: str,
|
||||
release_notes: str,
|
||||
notify_testers: Optional[bool] = None,
|
||||
branch_name: Optional[str] = None,
|
||||
commit_hash: Optional[str] = None,
|
||||
commit_message: Optional[str] = None,
|
||||
notify_testers: bool | None = None,
|
||||
branch_name: str | None = None,
|
||||
commit_hash: str | None = None,
|
||||
commit_message: str | None = None,
|
||||
) -> ReleaseDetailsResponse:
|
||||
"""Get the App Center release identifier for the app version (usually build number).
|
||||
|
||||
|
@ -668,10 +641,10 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
:param str binary_path: The path to the binary to upload
|
||||
:param str group_id: The ID of the group to release to
|
||||
:param str release_notes: The release notes for the release
|
||||
:param Optional[bool] notify_testers: Set to True to notify testers about this build
|
||||
:param Optional[str] branch_name: The git branch that the build came from
|
||||
:param Optional[str] commit_hash: The hash of the commit that was just built
|
||||
:param Optional[str] commit_message: The message of the commit that was just built
|
||||
:param bool | None notify_testers: Set to True to notify testers about this build
|
||||
:param str | None branch_name: The git branch that the build came from
|
||||
:param str | None commit_hash: The hash of the commit that was just built
|
||||
:param str | None commit_message: The message of the commit that was just built
|
||||
|
||||
:raises FileNotFoundError: If the supplied binary is not found
|
||||
:raises Exception: If we don't get a release ID back after upload
|
||||
|
@ -700,6 +673,6 @@ class AppCenterVersionsClient(AppCenterDerivedClient):
|
|||
notify_testers=notify_testers if notify_testers else False,
|
||||
)
|
||||
|
||||
return self.release_details(
|
||||
owner_name=owner_name, app_name=app_name, release_id=release_id
|
||||
)
|
||||
return self.release_details(owner_name=owner_name, app_name=app_name, release_id=release_id)
|
||||
|
||||
# pylint: enable=too-many-arguments
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -20,16 +20,16 @@ classifiers = [
|
|||
'Development Status :: 3 - Alpha',
|
||||
'Intended Audience :: Developers',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: 3.11',
|
||||
'Programming Language :: Python :: 3.12',
|
||||
'Topic :: Software Development',
|
||||
'Topic :: Utilities'
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
python = "^3.9"
|
||||
azure-storage-blob = "^2.1.0"
|
||||
deserialize = "^2.0.1"
|
||||
requests = "^2.31.0"
|
||||
|
@ -37,11 +37,11 @@ tenacity = "^8.2.2"
|
|||
types-requests = "^2.31.0.2"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
black = "^23.7.0"
|
||||
mypy = "^1.4.1"
|
||||
pylint = "^2.17.5"
|
||||
pytest = "^7.4.0"
|
||||
pytest-cov = "^4.1.0"
|
||||
black = "24.4.2"
|
||||
mypy = "1.10.0"
|
||||
pylint = "3.1.0"
|
||||
pytest = "^8.2.0"
|
||||
pytest-cov = "^5.0.0"
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
|
|
|
@ -9,7 +9,6 @@ import os
|
|||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import List, Optional
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
@ -22,7 +21,7 @@ import appcenter
|
|||
# pylint: disable=redefined-outer-name
|
||||
|
||||
|
||||
def get_from_keychain() -> Optional[str]:
|
||||
def get_from_keychain() -> str | None:
|
||||
"""Get the test details from the keychain.
|
||||
|
||||
:returns: A string with the details (colon separated)
|
||||
|
@ -44,9 +43,7 @@ def get_from_keychain() -> Optional[str]:
|
|||
return None
|
||||
|
||||
# The output is somewhat complex. We are looking for the line starting "password:"
|
||||
password_lines = [
|
||||
line for line in output.split("\n") if line.startswith("password: ")
|
||||
]
|
||||
password_lines = [line for line in output.split("\n") if line.startswith("password: ")]
|
||||
|
||||
if len(password_lines) != 1:
|
||||
raise Exception("Failed to get password from security output")
|
||||
|
@ -71,7 +68,7 @@ def get_from_keychain() -> Optional[str]:
|
|||
return password
|
||||
|
||||
|
||||
def get_tokens() -> List[str]:
|
||||
def get_tokens() -> list[str]:
|
||||
"""Get the tokens for authentication.
|
||||
|
||||
:returns: The owner name, app name and token as a tuple.
|
||||
|
@ -212,9 +209,7 @@ def test_release_details(owner_name: str, app_name: str, token: str):
|
|||
def test_latest_commit(owner_name: str, app_name: str, token: str):
|
||||
"""Test release details."""
|
||||
client = appcenter.AppCenterClient(access_token=token)
|
||||
commit_hash = client.versions.latest_commit(
|
||||
owner_name=owner_name, app_name=app_name
|
||||
)
|
||||
commit_hash = client.versions.latest_commit(owner_name=owner_name, app_name=app_name)
|
||||
assert commit_hash is not None
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче