Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
39 changes: 31 additions & 8 deletions src/azure-cli-core/azure/cli/core/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import argparse

from azure.cli.core.commands import ExtensionCommandSource
from azure.cli.core.util import in_cloud_console

from knack.help import (HelpFile as KnackHelpFile, CommandHelpFile as KnackCommandHelpFile,
GroupHelpFile as KnackGroupHelpFile, ArgumentGroupRegistry as KnackArgumentGroupRegistry,
Expand Down Expand Up @@ -77,14 +78,31 @@ def _print_examples(help_file):
from colorama import Style
indent = 0
_print_indent('Examples', indent)
for e in help_file.examples:
indent = 1
_print_indent(u'{0}'.format(e.short_summary), indent)
indent = 2
if e.long_summary:
_print_indent(u'{0}'.format(e.long_summary), indent)
_print_indent(u'{0}'.format(e.command), indent)
print('')
use_default_examples = True
# TODO: Once Python 3.8 support is added, switch to an Assignment
# Expressions to check if the the generated example list is not empty.
# That way it can fall back to the default one if there was a server
# error more elegantly.
if in_cloud_console():
examples = AzCliHelp.get_generated_examples(help_file.command)
if examples:
use_default_examples = False
for e in examples:
indent = 1
_print_indent(u'{0}'.format(e.title), indent)
indent = 2
_print_indent(u'{0}'.format(e.snippet), indent)
print('')

if use_default_examples:
for e in help_file.examples:
indent = 1
_print_indent(u'{0}'.format(e.short_summary), indent)
indent = 2
if e.long_summary:
_print_indent(u'{0}'.format(e.long_summary), indent)
_print_indent(u'{0}'.format(e.command), indent)
print('')
indent = 0
message = 'For more specific examples, use: az find "az {}"'.format(help_file.command)
_print_indent(Style.BRIGHT + message + Style.RESET_ALL + '\n', indent)
Expand Down Expand Up @@ -188,6 +206,11 @@ def update_loaders_with_help_file_contents(self, nouns):
file_contents[name] = self._name_to_content[name]
self.versioned_loaders[ldr_cls_name].update_file_contents(file_contents)

# This method is meant to be overridden by one in the Find module.
@staticmethod
def get_generated_examples(command):
return []


class CliHelpFile(KnackHelpFile):

Expand Down
2 changes: 1 addition & 1 deletion src/azure-cli/azure/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from knack.completion import ARGCOMPLETE_ENV_NAME
from knack.log import get_logger

from azure.cli.core import get_default_cli
from azure.cli.utils import get_default_cli

import azure.cli.core.telemetry as telemetry

Expand Down
51 changes: 37 additions & 14 deletions src/azure-cli/azure/cli/command_modules/find/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ def process_query(cli_term):
if not cli_term:
logger.error('Please provide a search term e.g. az find "vm"')
else:
response = call_aladdin_service(cli_term)

print(random.choice(WAIT_MESSAGE), file=sys.stderr)
response = call_aladdin_service(cli_term)

Expand All @@ -50,23 +48,25 @@ def process_query(cli_term):
print("\nHere are the most common ways to use [" + cli_term + "]: \n", file=sys.stderr)

for answer in answer_list:
current_title = answer['title'].strip()
current_snippet = answer['snippet'].strip()
if current_title.startswith("az "):
current_title, current_snippet = current_snippet, current_title
current_title = current_title.split('\r\n')[0]
elif '```azurecli\r\n' in current_snippet:
start_index = current_snippet.index('```azurecli\r\n') + len('```azurecli\r\n')
current_snippet = current_snippet[start_index:]
current_snippet = current_snippet.replace('```', '').replace(current_title, '').strip()
current_snippet = re.sub(r'\[.*\]', '', current_snippet).strip()
print(style_message(current_title))
print(current_snippet + '\n')
cleaned_answer = Example.clean_from_http_answer(answer)
print(style_message(cleaned_answer.title))
print(cleaned_answer.snippet + '\n')
if has_pruned_answer:
print(style_message("More commands and examples are available in the latest version of the CLI. "
"Please update for the best experience.\n"))


def get_generated_examples(cli_term):
examples = []
response = call_aladdin_service(cli_term)

if response.status_code == 200:
for answer in json.loads(response.content):
examples.append(Example.clean_from_http_answer(answer))

return examples


def style_message(msg):
if should_enable_styling():
try:
Expand Down Expand Up @@ -118,3 +118,26 @@ def call_aladdin_service(query):
headers=headers)

return response


class Example:
'Common format for example information'

def __init__(self, title, snippet):
self.title = title
self.snippet = snippet

# Used to clean up the HTTP response
@staticmethod
def clean_from_http_answer(http_answer):
current_title = http_answer['title'].strip()
current_snippet = http_answer['snippet'].strip()
if current_title.startswith("az "):
current_title, current_snippet = current_snippet, current_title
current_title = current_title.split('\r\n')[0]
elif '```azurecli\r\n' in current_snippet:
start_index = current_snippet.index('```azurecli\r\n') + len('```azurecli\r\n')
current_snippet = current_snippet[start_index:]
current_snippet = current_snippet.replace('```', '').replace(current_title, '').strip()
current_snippet = re.sub(r'\[.*\]', '', current_snippet).strip()
return Example(current_title, current_snippet)
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,78 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import contextlib
import json
import unittest
import mock
import sys
import six
from six import StringIO
import requests

from azure.cli.command_modules.find.custom import call_aladdin_service
from azure.cli.core.mock import DummyCli
from azure.cli.command_modules.find.custom import Example, call_aladdin_service, get_generated_examples


def create_valid_http_response():
mock_response = requests.Response()
mock_response.status_code = 200
data = [{
'title': 'RunTestAutomation',
'snippet': 'az find'
}, {
'title': 'az test',
'snippet': 'The title'
}]
mock_response._content = json.dumps(data)
return mock_response


def create_empty_http_response():
mock_response = requests.Response()
mock_response.status_code = 200
data = []
mock_response._content = json.dumps(data)
return mock_response


class FindCustomCommandTest(unittest.TestCase):

def test_call_aladdin_service(self):
response = call_aladdin_service("RunTestAutomation")
self.assertEqual(200, response.status_code)
mock_response = create_valid_http_response()

with mock.patch('requests.get', return_value=(mock_response)):
response = call_aladdin_service('RunTestAutomation')
self.assertEqual(200, response.status_code)
self.assertEqual(2, len(json.loads(response.content)))

def test_example_clean_from_http_answer(self):
cleaned_responses = []
mock_response = create_valid_http_response()

for response in json.loads(mock_response.content):
cleaned_responses.append(Example.clean_from_http_answer(response))

self.assertEqual('RunTestAutomation', cleaned_responses[0].title)
self.assertEqual('az find', cleaned_responses[0].snippet)
self.assertEqual('The title', cleaned_responses[1].title)
self.assertEqual('az test', cleaned_responses[1].snippet)

def test_get_generated_examples_full(self):
examples = []
mock_response = create_valid_http_response()

with mock.patch('requests.get', return_value=(mock_response)):
examples = get_generated_examples('RunTestAutomation')

self.assertEqual('RunTestAutomation', examples[0].title)
self.assertEqual('az find', examples[0].snippet)
self.assertEqual('The title', examples[1].title)
self.assertEqual('az test', examples[1].snippet)

def test_get_generated_examples_empty(self):
examples = []
mock_response = create_empty_http_response()

with mock.patch('requests.get', return_value=(mock_response)):
examples = get_generated_examples('RunTestAutomation')

self.assertEqual(0, len(examples))


if __name__ == '__main__':
Expand Down
26 changes: 26 additions & 0 deletions src/azure-cli/azure/cli/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

def get_default_cli():
from azure.cli.core.azlogging import AzCliLogging
from azure.cli.core.commands import AzCliCommandInvoker
from azure.cli.core.parser import AzCliCommandParser
from azure.cli.core._config import GLOBAL_CONFIG_DIR, ENV_VAR_PREFIX
from azure.cli.core._help import AzCliHelp
from azure.cli.core.__init__ import MainCommandsLoader, AzCli
from azure.cli.core._output import AzOutputProducer

from azure.cli.command_modules.find.custom import get_generated_examples
AzCliHelp.get_generated_examples = get_generated_examples

return AzCli(cli_name='az',
config_dir=GLOBAL_CONFIG_DIR,
config_env_var_prefix=ENV_VAR_PREFIX,
commands_loader_cls=MainCommandsLoader,
invocation_cls=AzCliCommandInvoker,
parser_cls=AzCliCommandParser,
logging_cls=AzCliLogging,
output_cls=AzOutputProducer,
help_cls=AzCliHelp)