Retrieve run and runs in async
This commit is contained in:
Родитель
dd8abe6519
Коммит
19ac79f618
|
@ -1 +1,4 @@
|
|||
from .get_task import get_task
|
||||
from .get_run import get_run
|
||||
from .get_runs import get_runs
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import sys
|
||||
import logging
|
||||
import json
|
||||
from itertools import zip_longest
|
||||
|
||||
from a01.cli import cmd, arg
|
||||
from a01.output import output_in_table
|
||||
from a01.models import TaskCollection
|
||||
from a01.operations import query_tasks_by_run, query_run
|
||||
|
||||
import colorama
|
||||
|
||||
|
||||
@cmd('get run', desc='Retrieve a run')
|
||||
@arg('run_id', help='The run id.', positional=True)
|
||||
@arg('log', help="Include the failed tasks' logs.", option=('-l', '--log'))
|
||||
@arg('recording', option=('-r', '--recording'),
|
||||
help='Download the recording files in recording directory at current working directory. The recordings '
|
||||
'are flatten with the full test path as the file name if --az-mode is not specified. If --az-mode is '
|
||||
'set, the recording files are arranged in directory structure mimic Azure CLI source code.')
|
||||
@arg('show_all', option=['--show-all'], help='Show all the tasks results.')
|
||||
@arg('recording_az_mode', option=['--az-mode'],
|
||||
help='When download the recording files the files are arranged in directory structure mimic Azure CLI '
|
||||
'source code.')
|
||||
@arg('raw', help='For debug.')
|
||||
def get_run(run_id: str, log: bool = False, recording: bool = False, recording_az_mode: bool = False,
|
||||
show_all: bool = False, raw: bool = False) -> None:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
tasks = TaskCollection(query_tasks_by_run(run_id), run_id)
|
||||
output_in_table(tasks.get_table_view(failed=not show_all), headers=tasks.get_table_header())
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
if log:
|
||||
for failure in tasks.get_failed_tasks():
|
||||
output_in_table(zip_longest(failure.get_table_header(), failure.get_table_view()), tablefmt='plain')
|
||||
output_in_table(failure.get_log_content(), tablefmt='plain', foreground_color=colorama.Fore.CYAN)
|
||||
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
if recording:
|
||||
print()
|
||||
print('Download recordings ...')
|
||||
for task in tasks.tasks:
|
||||
task.download_recording(recording_az_mode)
|
||||
|
||||
if raw:
|
||||
run = query_run(run_id=run_id)
|
||||
print(json.dumps(run.to_dict(), indent=2))
|
||||
except ValueError as err:
|
||||
logger.error(err)
|
||||
sys.exit(1)
|
|
@ -0,0 +1,32 @@
|
|||
import logging
|
||||
import sys
|
||||
|
||||
from a01.auth import AuthSettings, AuthenticationError
|
||||
from a01.cli import cmd, arg
|
||||
from a01.operations import query_runs
|
||||
from a01.output import output_in_table
|
||||
|
||||
|
||||
@cmd('get runs', desc='Retrieve the runs.')
|
||||
@arg('owner', help='Query runs by owner.')
|
||||
@arg('me', help='Query runs created by me.')
|
||||
@arg('last', help='Returns the last NUMBER of records. Default: 20.')
|
||||
@arg('skip', help='Returns the records after skipping given number of records at the bottom. Default: 0.')
|
||||
def get_runs(me: bool = False, last: int = 20, skip: int = 0,
|
||||
owner: str = None) -> None: # pylint: disable=invalid-name
|
||||
logger = logging.getLogger(__name__)
|
||||
try:
|
||||
if me and owner:
|
||||
raise ValueError('--me and --user are mutually exclusive.')
|
||||
elif me:
|
||||
owner = AuthSettings().get_user_name()
|
||||
|
||||
runs = query_runs(owner=owner, last=last, skip=skip)
|
||||
output_in_table(runs.get_table_view(), headers=runs.get_table_header())
|
||||
except ValueError as err:
|
||||
logger.error(err)
|
||||
sys.exit(1)
|
||||
except AuthenticationError as err:
|
||||
logger.error(err)
|
||||
print('You need to login. Usage: a01 login.', file=sys.stderr)
|
||||
sys.exit(1)
|
|
@ -1,5 +1,5 @@
|
|||
# pylint: disable=unused-import
|
||||
|
||||
from .run import Run, RunCollection
|
||||
from .run import Run, RunsView
|
||||
from .task import Task
|
||||
from .task_collection import TaskCollection
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import json
|
||||
import datetime
|
||||
import urllib
|
||||
from typing import List, Tuple, Generator
|
||||
|
||||
import colorama
|
||||
|
@ -94,9 +93,7 @@ class Run(object):
|
|||
return config.endpoint_uri
|
||||
|
||||
|
||||
class RunCollection(object):
|
||||
logger = get_logger('RunCollection')
|
||||
|
||||
class RunsView(object):
|
||||
def __init__(self, runs: List[Run]) -> None:
|
||||
self.runs = runs
|
||||
|
||||
|
@ -117,35 +114,3 @@ class RunCollection(object):
|
|||
@staticmethod
|
||||
def get_table_header() -> Tuple:
|
||||
return 'Id', 'Name', 'Creation', 'Status', 'Remark', 'Owner'
|
||||
|
||||
@classmethod
|
||||
def get(cls, **kwargs) -> 'RunCollection':
|
||||
try:
|
||||
url = f'{cls.endpoint_uri()}/runs'
|
||||
query = {}
|
||||
for key, value in kwargs.items():
|
||||
if value is not None:
|
||||
query[key] = value
|
||||
|
||||
if query:
|
||||
url = f'{url}?{urllib.parse.urlencode(query)}'
|
||||
|
||||
resp = session.get(url)
|
||||
resp.raise_for_status()
|
||||
|
||||
runs = [Run.from_dict(each) for each in resp.json()]
|
||||
runs = sorted(runs, key=lambda r: r.id, reverse=True)
|
||||
|
||||
return RunCollection(runs)
|
||||
except HTTPError:
|
||||
cls.logger.debug('HttpError', exc_info=True)
|
||||
raise ValueError('Fail to get runs.')
|
||||
except (KeyError, json.JSONDecodeError, TypeError):
|
||||
cls.logger.debug('JsonError', exc_info=True)
|
||||
raise ValueError('Fail to parse the runs data.')
|
||||
|
||||
@staticmethod
|
||||
def endpoint_uri():
|
||||
config = A01Config()
|
||||
config.ensure_config()
|
||||
return config.endpoint_uri
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
from .query_tasks import query_tasks
|
||||
from .query_tasks import query_tasks, query_tasks_by_run
|
||||
from .query_runs import query_run, query_runs
|
|
@ -0,0 +1,41 @@
|
|||
from urllib.parse import urlencode
|
||||
|
||||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
from a01.auth import AuthSettings
|
||||
from a01.common import A01Config
|
||||
from a01.models import Run, RunsView
|
||||
|
||||
|
||||
async def query_run_async(run_id: str) -> Run:
|
||||
endpoint = A01Config().ensure_config().endpoint_uri
|
||||
async with aiohttp.ClientSession(headers={'Authorization': AuthSettings().access_token}) as session:
|
||||
async with session.get(f'{endpoint}/run/{run_id}') as resp:
|
||||
json_body = await resp.json()
|
||||
return Run.from_dict(json_body)
|
||||
|
||||
|
||||
async def query_runs_async(**kwargs) -> RunsView:
|
||||
endpoint = A01Config().ensure_config().endpoint_uri
|
||||
async with aiohttp.ClientSession(headers={'Authorization': AuthSettings().access_token}) as session:
|
||||
url = f'{endpoint}/runs'
|
||||
query = {}
|
||||
for key, value in kwargs.items():
|
||||
if value is not None:
|
||||
query[key] = value
|
||||
|
||||
if query:
|
||||
url = f'{url}?{urlencode(query)}'
|
||||
|
||||
async with session.get(url) as resp:
|
||||
json_body = await resp.json()
|
||||
return RunsView(runs=[Run.from_dict(each) for each in json_body])
|
||||
|
||||
|
||||
def query_run(run_id: str) -> Run:
|
||||
return asyncio.get_event_loop().run_until_complete(query_run_async(run_id))
|
||||
|
||||
|
||||
def query_runs(owner: str = None, last: int = 10, skip: int = 0) -> RunsView:
|
||||
return asyncio.get_event_loop().run_until_complete(query_runs_async(owner=owner, last=last, skip=skip))
|
|
@ -3,18 +3,15 @@ from typing import List
|
|||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
from a01.auth import AuthSettings
|
||||
from a01.common import A01Config
|
||||
from a01.models import Task
|
||||
from a01.auth import AuthSettings
|
||||
|
||||
|
||||
async def query_tasks_async(ids: List[str]) -> List[Task]:
|
||||
endpoint = A01Config().ensure_config().endpoint_uri
|
||||
access_token = AuthSettings().access_token
|
||||
headers = {'Authorization': access_token}
|
||||
|
||||
results = []
|
||||
async with aiohttp.ClientSession(headers=headers) as session:
|
||||
endpoint = A01Config().ensure_config().endpoint_uri
|
||||
async with aiohttp.ClientSession(headers={'Authorization': AuthSettings().access_token}) as session:
|
||||
for task_id in ids:
|
||||
async with session.get(f'{endpoint}/task/{task_id}') as resp:
|
||||
json_body = await resp.json()
|
||||
|
@ -23,8 +20,17 @@ async def query_tasks_async(ids: List[str]) -> List[Task]:
|
|||
return results
|
||||
|
||||
|
||||
def query_tasks(ids: List[str]) -> List[Task]:
|
||||
loop = asyncio.get_event_loop()
|
||||
tasks = loop.run_until_complete(query_tasks_async(ids))
|
||||
async def query_tasks_by_run_async(run_id: str) -> List[Task]:
|
||||
endpoint = A01Config().ensure_config().endpoint_uri
|
||||
async with aiohttp.ClientSession(headers={'Authorization': AuthSettings().access_token}) as session:
|
||||
async with session.get(f'{endpoint}/run/{run_id}/tasks') as resp:
|
||||
json_body = await resp.json()
|
||||
return [Task.from_dict(data) for data in json_body]
|
||||
|
||||
return tasks
|
||||
|
||||
def query_tasks(ids: List[str]) -> List[Task]:
|
||||
return asyncio.get_event_loop().run_until_complete(query_tasks_async(ids))
|
||||
|
||||
|
||||
def query_tasks_by_run(run_id: str) -> List[Task]:
|
||||
return asyncio.get_event_loop().run_until_complete(query_tasks_by_run_async(run_id))
|
||||
|
|
|
@ -1,86 +1,17 @@
|
|||
import json
|
||||
import sys
|
||||
from itertools import zip_longest
|
||||
|
||||
import colorama
|
||||
|
||||
import a01
|
||||
import a01.models
|
||||
from a01.common import get_logger, A01Config
|
||||
from a01.cli import cmd, arg
|
||||
from a01.communication import session
|
||||
from a01.auth import AuthSettings, AuthenticationError
|
||||
from a01.output import output_in_table
|
||||
from a01.auth import AuthSettings
|
||||
|
||||
# pylint: disable=too-many-arguments, invalid-name
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@cmd('get runs', desc='Retrieve the runs.')
|
||||
@arg('owner', help='Query runs by owner.')
|
||||
@arg('me', help='Query runs created by me.')
|
||||
@arg('last', help='Returns the last NUMBER of records. Default: 20.')
|
||||
@arg('skip', help='Returns the records after skipping given number of records at the bottom. Default: 0.')
|
||||
def get_runs(me: bool = False, last: int = 20, skip: int = 0,
|
||||
owner: str = None) -> None: # pylint: disable=invalid-name
|
||||
try:
|
||||
if me and owner:
|
||||
raise ValueError('--me and --user are mutually exclusive.')
|
||||
elif me:
|
||||
owner = AuthSettings().get_user_name()
|
||||
|
||||
runs = a01.models.RunCollection.get(owner=owner, last=last, skip=skip)
|
||||
output_in_table(runs.get_table_view(), headers=runs.get_table_header())
|
||||
except ValueError as err:
|
||||
logger.error(err)
|
||||
sys.exit(1)
|
||||
except AuthenticationError as err:
|
||||
logger.error(err)
|
||||
print('You need to login. Usage: a01 login.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@cmd('get run', desc='Retrieve a run')
|
||||
@arg('run_id', help='The run id.', positional=True)
|
||||
@arg('log', help="Include the failed tasks' logs.", option=('-l', '--log'))
|
||||
@arg('recording', option=('-r', '--recording'),
|
||||
help='Download the recording files in recording directory at current working directory. The recordings '
|
||||
'are flatten with the full test path as the file name if --az-mode is not specified. If --az-mode is '
|
||||
'set, the recording files are arranged in directory structure mimic Azure CLI source code.')
|
||||
@arg('show_all', option=['--show-all'], help='Show all the tasks results.')
|
||||
@arg('recording_az_mode', option=['--az-mode'],
|
||||
help='When download the recording files the files are arranged in directory structure mimic Azure CLI '
|
||||
'source code.')
|
||||
@arg('raw', help='For debug.')
|
||||
def get_run(run_id: str, log: bool = False, recording: bool = False, recording_az_mode: bool = False,
|
||||
show_all: bool = False, raw: bool = False) -> None:
|
||||
try:
|
||||
tasks = a01.models.TaskCollection.get(run_id=run_id)
|
||||
output_in_table(tasks.get_table_view(failed=not show_all), headers=tasks.get_table_header())
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
if log:
|
||||
for failure in tasks.get_failed_tasks():
|
||||
output_in_table(zip_longest(failure.get_table_header(), failure.get_table_view()), tablefmt='plain')
|
||||
output_in_table(failure.get_log_content(), tablefmt='plain', foreground_color=colorama.Fore.CYAN)
|
||||
|
||||
output_in_table(tasks.get_summary(), tablefmt='plain')
|
||||
|
||||
if recording:
|
||||
print()
|
||||
print('Download recordings ...')
|
||||
for task in tasks.tasks:
|
||||
task.download_recording(recording_az_mode)
|
||||
|
||||
if raw:
|
||||
run = a01.models.Run.get(run_id=run_id)
|
||||
print(json.dumps(run.to_dict(), indent=2))
|
||||
except ValueError as err:
|
||||
logger.error(err)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@cmd('create run', desc='Create a new run.')
|
||||
@arg('image', help='The droid image to run.', positional=True)
|
||||
@arg('parallelism', option=('-p', '--parallelism'),
|
||||
|
|
Загрузка…
Ссылка в новой задаче