Skip to content

Commit 3b507dc

Browse files
authored
Add new command command-change tree-export to export command tree (#448)
* Add new command `command-change tree-export` to export command tree * Fix style * apply suggestions * Update version * Extract tree build and add test
1 parent 6b2b150 commit 3b507dc

File tree

7 files changed

+100
-3
lines changed

7 files changed

+100
-3
lines changed

HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
33
Release History
44
===============
5+
0.1.68
6+
++++++
7+
* `azdev command-change tree-export`: Add new command to support export command tree of CLI modules.
8+
59
0.1.67
610
++++++
711
* `azdev extension cal-next-version`: Justify preview/exp tag operation based on last version's tag and next version's stable/preview tag.

azdev/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
# license information.
55
# -----------------------------------------------------------------------------
66

7-
__VERSION__ = '0.1.67'
7+
__VERSION__ = '0.1.68'

azdev/commands.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def operation_group(name):
4040
with CommandGroup(self, 'command-change', operation_group('command_change')) as g:
4141
g.command('meta-export', 'export_command_meta')
4242
g.command('meta-diff', 'cmp_command_meta')
43+
g.command('tree-export', 'export_command_tree')
4344

4445
with CommandGroup(self, 'cli', operation_group('pypi')) as g:
4546
g.command('check-versions', 'verify_versions')

azdev/operations/command_change/__init__.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import azure_cli_diff_tool
1313
from azdev.utilities import display, require_azure_cli, heading, get_path_table, filter_by_git_diff
1414
from .custom import DiffExportFormat, get_commands_meta, STORED_DEPRECATION_KEY
15-
from .util import export_commands_meta
15+
from .util import export_commands_meta, dump_command_tree, add_to_command_tree
1616
from ..statistics import _create_invoker_and_load_cmds, _get_command_source, \
1717
_command_codegen_info # pylint: disable=protected-access
1818
from ..statistics.util import filter_modules
@@ -129,3 +129,60 @@ def export_command_meta(modules=None, git_source=None, git_target=None, git_repo
129129

130130
def cmp_command_meta(base_meta_file, diff_meta_file, only_break=False, output_type="text", output_file=None):
131131
return azure_cli_diff_tool.meta_diff(base_meta_file, diff_meta_file, only_break, output_type, output_file)
132+
133+
134+
def export_command_tree(modules, output_file=None):
135+
require_azure_cli()
136+
137+
# allow user to run only on CLI or extensions
138+
cli_only = modules == ['CLI']
139+
ext_only = modules == ['EXT']
140+
if cli_only or ext_only:
141+
modules = None
142+
143+
selected_modules = get_path_table(include_only=modules)
144+
145+
if cli_only:
146+
selected_modules['ext'] = {}
147+
if ext_only:
148+
selected_modules['core'] = {}
149+
selected_modules['mod'] = {}
150+
151+
if not any(selected_modules.values()):
152+
logger.warning('No commands selected to check.')
153+
154+
selected_mod_names = list(selected_modules['mod'].keys())
155+
selected_mod_names += list(selected_modules['ext'].keys())
156+
selected_mod_names += list(selected_modules['core'].keys())
157+
158+
if selected_mod_names:
159+
display('Modules selected: {}\n'.format(', '.join(selected_mod_names)))
160+
161+
heading('Export Command Tree')
162+
start = time.time()
163+
display('Initializing with loading command table...')
164+
from azure.cli.core import get_default_cli # pylint: disable=import-error
165+
az_cli = get_default_cli()
166+
167+
# load commands, args, and help
168+
_create_invoker_and_load_cmds(az_cli)
169+
170+
stop = time.time()
171+
logger.info('Commands loaded in %i sec', stop - start)
172+
display('Commands loaded in {} sec'.format(stop - start))
173+
command_loader = az_cli.invocation.commands_loader
174+
175+
# trim command table to selected_modules
176+
command_loader = filter_modules(command_loader, modules=selected_mod_names)
177+
178+
if not command_loader.command_table:
179+
logger.warning('No commands selected to check.')
180+
181+
command_tree = {}
182+
183+
for command_name, command in command_loader.command_table.items():
184+
module_source = _get_command_source(command_name, command)['module']
185+
# The command tree is a tree structure like our azExtCmdTree: https://aka.ms/azExtCmdTree
186+
add_to_command_tree(command_tree, command_name, module_source)
187+
188+
dump_command_tree(command_tree, output_file)

azdev/operations/command_change/util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,18 @@ def export_commands_meta(commands_meta, meta_output_path=None):
7373
os.makedirs(file_folder)
7474
with open(file_name, "w") as f_out:
7575
f_out.write(jsbeautifier.beautify(json.dumps(module_info), options))
76+
77+
78+
def add_to_command_tree(tree, key, value):
79+
parts = key.split()
80+
subtree = tree
81+
for part in parts[:-1]:
82+
if not subtree.get(part):
83+
subtree[part] = {}
84+
subtree = subtree[part]
85+
subtree[parts[-1]] = value
86+
87+
88+
def dump_command_tree(command_tree, output_file):
89+
with open(output_file, 'w', encoding='utf-8') as f:
90+
json.dump(command_tree, f, indent=4)

azdev/operations/tests/test_break_change.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import unittest
99
import os
1010
from azdev.operations.command_change import export_command_meta, cmp_command_meta
11-
from azdev.operations.command_change.util import get_command_tree
11+
from azdev.operations.command_change.util import get_command_tree, add_to_command_tree
1212

1313

1414
class MyTestCase(unittest.TestCase):
@@ -57,6 +57,22 @@ def test_diff_meta(self):
5757
break
5858
self.assertTrue(ignored, "ignored message found")
5959

60+
def test_command_tree(self):
61+
tree = {}
62+
add_to_command_tree(tree, 'a b c', 'd')
63+
add_to_command_tree(tree, 'a b foo', 'bar')
64+
add_to_command_tree(tree, 'a foo', 'baz')
65+
expected = {
66+
'a': {
67+
'b': {
68+
'c': 'd',
69+
'foo': 'bar'
70+
},
71+
'foo': 'baz'
72+
}
73+
}
74+
self.assertDictEqual(tree, expected)
75+
6076

6177
if __name__ == '__main__':
6278
unittest.main()

azdev/params.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ def load_arguments(self, _):
129129
help='format to print diff and suggest message')
130130
c.argument('output_file', help='command meta diff json file path to store')
131131

132+
with ArgumentsContext(self, 'command-change tree-export') as c:
133+
c.positional('modules', modules_type)
134+
c.argument('output_file', help='command tree json file path to store')
135+
132136
# region cmdcov
133137
with ArgumentsContext(self, 'cmdcov') as c:
134138
c.positional('modules', modules_type)

0 commit comments

Comments
 (0)