Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Enhancements

* Added `globus flows registered-api list` command to list registered APIs
1 change: 1 addition & 0 deletions src/globus_cli/commands/flows/registered_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"registered-api",
lazy_subcommands={
"show": (".show", "show_command"),
"list": (".list", "list_command"),
},
)
def registered_api_command() -> None:
Expand Down
92 changes: 92 additions & 0 deletions src/globus_cli/commands/flows/registered_api/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
from __future__ import annotations

import typing as t

import click
import globus_sdk
from globus_sdk.paging import Paginator

from globus_cli.login_manager import LoginManager
from globus_cli.parsing import ColonDelimitedChoiceTuple, command
from globus_cli.termio import Field, display, formatters
from globus_cli.utils import PagingWrapper

ROLE_TYPES = ("owner", "administrator", "viewer")
ORDER_BY_FIELDS = ("id", "name", "created_timestamp", "updated_timestamp")


@command("list")
@click.option(
"--filter-role",
"filter_roles",
type=click.Choice(ROLE_TYPES),
help="Filter results by the registered API's role type associated with the caller",
multiple=True,
)
@click.option(
"--orderby",
default=("created_timestamp:DESC",),
show_default=True,
type=ColonDelimitedChoiceTuple(
choices=tuple(
f"{field}:{order}" for field in ORDER_BY_FIELDS for order in ("ASC", "DESC")
),
case_sensitive=False,
),
multiple=True,
metavar=f"[{'|'.join(ORDER_BY_FIELDS)}]:[ASC|DESC]",
help="""
Sort results by the given field and ordering.
ASC for ascending, DESC for descending.

This option can be specified multiple times to sort by multiple fields.
""",
)
@click.option(
"--limit",
default=25,
show_default=True,
metavar="N",
type=click.IntRange(1),
help="The maximum number of results to return.",
)
@LoginManager.requires_login("flows")
def list_command(
login_manager: LoginManager,
*,
filter_roles: tuple[t.Literal["owner", "administrator", "viewer"], ...],
orderby: tuple[
tuple[
t.Literal["id", "name", "created_timestamp", "updated_timestamp"],
t.Literal["ASC", "DESC"],
],
...,
],
limit: int,
) -> None:
"""
List registered APIs.
"""
flows_client = login_manager.get_flows_client()
paginator = Paginator.wrap(flows_client.list_registered_apis)
api_iterator = PagingWrapper(
paginator(
filter_roles=filter_roles or globus_sdk.MISSING,
orderby=",".join(f"{field} {order}" for field, order in orderby),
Comment thread
kurtmckee marked this conversation as resolved.
).items(),
json_conversion_key="registered_apis",
limit=limit,
)

fields = [
Field("Registered API ID", "id"),
Field("Name", "name"),
Field("Created At", "created_timestamp", formatter=formatters.Date),
Field("Updated At", "updated_timestamp", formatter=formatters.Date),
]

display(
api_iterator,
fields=fields,
json_converter=api_iterator.json_converter,
)
148 changes: 148 additions & 0 deletions tests/functional/flows/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,3 +302,151 @@ def _load_identities_for_registered_api(
return pool

return _load_identities_for_registered_api


def generate_registered_api_summary(
n: int, *, name: str | None = None
) -> dict[str, t.Any]:
"""Generate a summary registered API object for list responses."""
api_id = str(uuid.UUID(int=n))
base_time = datetime.datetime.fromisoformat("2023-12-31T18:00:00")
created_timestamp = base_time + datetime.timedelta(days=n)
updated_timestamp = created_timestamp + datetime.timedelta(hours=n)

return {
"id": api_id,
"name": name or f"registered-api-{n}",
"description": f"Test registered API number {n}",
"created_timestamp": created_timestamp.isoformat(),
"updated_timestamp": updated_timestamp.isoformat(),
}


@pytest.fixture(autouse=True, scope="session")
def setup_registered_apis_list_responses() -> None:
register_response_set(
"cli.registered_apis_list",
{
"default": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
generate_registered_api_summary(1),
generate_registered_api_summary(0),
],
"limit": 25,
"has_next_page": False,
"marker": None,
},
"match": [
matchers.query_param_matcher({"orderby": "created_timestamp DESC"})
],
},
},
)

register_response_set(
"cli.registered_apis_list_filtered",
{
"default": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
generate_registered_api_summary(2),
generate_registered_api_summary(1),
generate_registered_api_summary(0),
],
"limit": 25,
"has_next_page": False,
"marker": None,
},
},
},
)

register_response_set(
"registered_apis_list_paginated",
{
"page0": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
generate_registered_api_summary(i) for i in range(10)
],
"limit": 10,
"has_next_page": True,
"marker": "fake_marker_0",
},
"match": [
matchers.query_param_matcher({"orderby": "created_timestamp DESC"})
],
},
"page1": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
generate_registered_api_summary(i) for i in range(10, 20)
],
"limit": 10,
"has_next_page": True,
"marker": "fake_marker_1",
},
"match": [
matchers.query_param_matcher(
{"orderby": "created_timestamp DESC", "marker": "fake_marker_0"}
)
],
},
"page2": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
generate_registered_api_summary(i) for i in range(20, 25)
],
"limit": 5,
"has_next_page": False,
"marker": None,
},
"match": [
matchers.query_param_matcher(
{"orderby": "created_timestamp DESC", "marker": "fake_marker_1"}
)
],
},
},
metadata={
"num_pages": 3,
"expect_markers": ["fake_marker_0", "fake_marker_1", None],
"total_items": 25,
},
)

register_response_set(
"registered_apis_list_orderby_name_asc",
{
"name_asc": {
"service": "flows",
"path": "/registered_apis",
"json": {
"registered_apis": [
# chr(65) = 'A', so this is A-Z
generate_registered_api_summary(
i, name=f"{chr(65 + i)}-Sorted-API"
)
for i in range(26)
],
"limit": 100,
"has_next_page": False,
},
"match": [matchers.query_param_matcher({"orderby": "name ASC"})],
},
},
metadata={
"total_items": 26,
},
)
Loading
Loading