diff --git a/linodecli/arg_helpers.py b/linodecli/arg_helpers.py index b112c6ec6..0b3f50f4f 100644 --- a/linodecli/arg_helpers.py +++ b/linodecli/arg_helpers.py @@ -5,6 +5,7 @@ import os import sys +import textwrap from importlib import import_module import requests @@ -349,13 +350,30 @@ def action_help(cli, command, action): except ValueError: return print(f"linode-cli {command} {action}", end="") + for param in op.params: pname = param.name.upper() print(f" [{pname}]", end="") + print() print(op.summary) + if op.docs_url: rprint(f"API Documentation: [link={op.docs_url}]{op.docs_url}[/link]") + + if len(op.samples) > 0: + print() + print(f"Example Usage{'s' if len(op.samples) > 1 else ''}: ") + + rprint( + *[ + # Indent all samples for readability; strip and trailing newlines + textwrap.indent(v.get("source").rstrip(), " ") + for v in op.samples + ], + sep="\n\n", + ) + print() if op.method == "get" and op.action == "list": filterable_attrs = [ diff --git a/linodecli/baked/operation.py b/linodecli/baked/operation.py index 3441cb949..5a5ec7c03 100644 --- a/linodecli/baked/operation.py +++ b/linodecli/baked/operation.py @@ -311,6 +311,13 @@ def __init__(self, command, operation: Operation, method, params): ) self.docs_url = docs_url + code_samples_ext = operation.extensions.get("code-samples") + self.samples = ( + [v for v in code_samples_ext if v.get("lang").lower() == "cli"] + if code_samples_ext is not None + else [] + ) + @property def args(self): """ diff --git a/requirements-dev.txt b/requirements-dev.txt index cf106f3ec..4c7268f99 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,4 +8,3 @@ requests-mock==1.11.0 boto3-stubs[s3] build>=0.10.0 twine>=4.0.2 -packaging>=23.2 diff --git a/tests/unit/test_arg_helpers.py b/tests/unit/test_arg_helpers.py index 3fa1eb37b..99b65fdc3 100644 --- a/tests/unit/test_arg_helpers.py +++ b/tests/unit/test_arg_helpers.py @@ -179,6 +179,10 @@ def test_action_help_post_method(self, capsys, mocker, mock_cli): mocked_ops.summary = "test summary" mocked_ops.docs_url = "https://website.com/endpoint" mocked_ops.method = "post" + mocked_ops.samples = [ + {"lang": "CLI", "source": "linode-cli command action\n --foo=bar"}, + {"lang": "CLI", "source": "linode-cli command action\n --bar=foo"}, + ] mocked_args = mocker.MagicMock() mocked_args.read_only = False @@ -196,6 +200,13 @@ def test_action_help_post_method(self, capsys, mocker, mock_cli): assert "test summary" in captured.out assert "API Documentation" in captured.out assert "https://website.com/endpoint" in captured.out + assert ( + "Example Usages: \n" + " linode-cli command action\n" + " --foo=bar\n\n" + " linode-cli command action\n" + " --bar=foo\n\n" + ) in captured.out assert "Arguments" in captured.out assert "test description" in captured.out assert "(required)" in captured.out @@ -208,6 +219,9 @@ def test_action_help_get_method(self, capsys, mocker, mock_cli): mocked_ops.method = "get" mocked_ops.action = "list" mocked_ops.args = None + mocked_ops.samples = [ + {"lang": "CLI", "source": "linode-cli command action"} + ] mock_attr = mocker.MagicMock() mock_attr.filterable = True @@ -221,6 +235,7 @@ def test_action_help_get_method(self, capsys, mocker, mock_cli): assert "test summary" in captured.out assert "API Documentation" in captured.out assert "https://website.com/endpoint" in captured.out + assert "Example Usage: \n linode-cli command action" in captured.out assert "Arguments" not in captured.out assert "filter results" in captured.out assert "filtername" in captured.out