Skip to content

Commit 04c1e92

Browse files
new: Break out command help page logic; sort actions in output (#638)
1 parent c0a860c commit 04c1e92

File tree

4 files changed

+94
-19
lines changed

4 files changed

+94
-19
lines changed

linodecli/__init__.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .help_pages import (
2828
HELP_TOPICS,
2929
print_help_action,
30+
print_help_command_actions,
3031
print_help_commands,
3132
print_help_default,
3233
print_help_env_vars,
@@ -224,23 +225,7 @@ def main(): # pylint: disable=too-many-branches,too-many-statements
224225
and parsed.action is None
225226
and parsed.command in cli.ops
226227
):
227-
print(f"linode-cli {parsed.command} [ACTION]")
228-
print()
229-
print("Available actions: ")
230-
231-
content = [
232-
[", ".join([action, *op.action_aliases]), op.summary]
233-
for action, op in cli.ops[parsed.command].items()
234-
]
235-
236-
table = Table(
237-
Column(header="action", no_wrap=True),
238-
Column(header="summary", style="cyan"),
239-
)
240-
for row in content:
241-
table.add_row(*row)
242-
243-
rprint(table)
228+
print_help_command_actions(cli.ops, parsed.command)
244229
sys.exit(ExitCodes.SUCCESS)
245230

246231
if parsed.command is not None and parsed.action is not None:

linodecli/help_pages.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
help pages.
44
"""
55

6+
import sys
67
import textwrap
78
from collections import defaultdict
8-
from typing import List, Optional
9+
from typing import Dict, List, Optional
910

1011
from rich import box
1112
from rich import print as rprint
1213
from rich.console import Console
1314
from rich.padding import Padding
14-
from rich.table import Table
15+
from rich.table import Column, Table
1516
from rich.text import Text
1617

1718
from linodecli import plugins
@@ -140,6 +141,36 @@ def print_help_default():
140141
)
141142

142143

144+
def print_help_command_actions(
145+
ops: Dict[str, Dict[str, OpenAPIOperation]],
146+
command: Optional[str],
147+
file=sys.stdout,
148+
):
149+
"""
150+
Prints the help page for a single command, including all actions
151+
under the given command.
152+
153+
:param ops: A dictionary mapping CLI commands -> actions -> operations.
154+
:param command: The command to print the help page for.
155+
"""
156+
157+
print(f"linode-cli {command} [ACTION]\n\nAvailable actions: ", file=file)
158+
159+
content = [
160+
[", ".join([action, *op.action_aliases]), op.summary]
161+
for action, op in sorted(ops[command].items(), key=lambda v: v[0])
162+
]
163+
164+
table = Table(
165+
Column(header="action", no_wrap=True),
166+
Column(header="summary", style="cyan"),
167+
)
168+
for row in content:
169+
table.add_row(*row)
170+
171+
rprint(table, file=file)
172+
173+
143174
def print_help_action(
144175
cli: "CLI", command: Optional[str], action: Optional[str]
145176
):

tests/unit/conftest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import configparser
2+
from typing import List
23

34
import pytest
45
from openapi3 import OpenAPI
@@ -321,3 +322,22 @@ def write_config(self): # pylint: disable=missing-function-docstring
321322
pass
322323

323324
return Config()
325+
326+
327+
def assert_contains_ordered_substrings(target: str, entries: List[str]):
328+
"""
329+
Asserts whether the given string contains the given entries in order,
330+
ignoring any irrelevant characters in-between.
331+
332+
:param target: The string to search.
333+
:param entries: The ordered list of entries to search for.
334+
"""
335+
336+
start_index = 0
337+
338+
for entry in entries:
339+
find_index = target[start_index:].find(entry)
340+
assert find_index >= 0
341+
342+
# Search for the next entry after the end of this entry
343+
start_index = find_index + len(entry)

tests/unit/test_help_pages.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
from io import StringIO
12
from types import SimpleNamespace
23

34
from linodecli import help_pages
5+
from tests.unit.conftest import assert_contains_ordered_substrings
46

57

68
class TestHelpPages:
@@ -175,3 +177,40 @@ def test_action_help_post_method(self, capsys, mocker, mock_cli):
175177
assert "(required, nullable, conflicts with children)" in captured.out
176178
assert "(JSON, nullable, conflicts with children)" in captured.out
177179
assert "filter results" not in captured.out
180+
181+
def test_help_command_actions(self, mocker):
182+
test_operations = {
183+
"foo": {
184+
"b-create": mocker.MagicMock(
185+
summary="Test summary.", action_aliases=[]
186+
),
187+
"b-list": mocker.MagicMock(
188+
summary="Test summary 2.", action_aliases=["b-ls"]
189+
),
190+
"a-list": mocker.MagicMock(
191+
summary="Test summary 3.", action_aliases=["a-ls"]
192+
),
193+
}
194+
}
195+
196+
stdout_buffer = StringIO()
197+
help_pages.print_help_command_actions(
198+
test_operations, "foo", file=stdout_buffer
199+
)
200+
201+
# Ensure the given snippets are printed in order, ignoring irrelevant characters
202+
assert_contains_ordered_substrings(
203+
stdout_buffer.getvalue(),
204+
[
205+
"linode-cli foo [ACTION]",
206+
"Available actions:",
207+
"action",
208+
"summary",
209+
"a-list, a-ls",
210+
"Test summary 3.",
211+
"b-create",
212+
"Test summary.",
213+
"b-list, b-ls",
214+
"Test summary 2.",
215+
],
216+
)

0 commit comments

Comments
 (0)