Hello community,

here is the log from the commit of package azure-cli-feedback for 
openSUSE:Factory checked in at 2019-05-22 11:00:09
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/azure-cli-feedback (Old)
 and      /work/SRC/openSUSE:Factory/.azure-cli-feedback.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "azure-cli-feedback"

Wed May 22 11:00:09 2019 rev:5 rq:696836 version:2.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/azure-cli-feedback/azure-cli-feedback.changes    
2018-10-15 10:44:37.435314408 +0200
+++ 
/work/SRC/openSUSE:Factory/.azure-cli-feedback.new.5148/azure-cli-feedback.changes
  2019-05-22 11:00:12.882752093 +0200
@@ -1,0 +2,15 @@
+Wed Apr 17 07:19:57 UTC 2019 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- New upstream release
+  + Version 2.2.0
+  + For detailed information about changes see the
+    HISTORY.txt file provided with this package
+- Bump minimum version for Python Azure SDK namespace
+  packages to 3.0.0 in BuildRequires and Requires
+- Remove python3-devel package from BuildRequires
+- Remove unzip package from BuildRequires
+- Run fdupes to hardlink duplicate files
+  + Add fdupes to BuildRequires
+  + Add %fdupes invocation to %install
+
+-------------------------------------------------------------------

Old:
----
  azure-cli-feedback-2.1.4.tar.gz

New:
----
  azure-cli-feedback-2.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ azure-cli-feedback.spec ++++++
--- /var/tmp/diff_new_pack.JEchYy/_old  2019-05-22 11:00:13.618751139 +0200
+++ /var/tmp/diff_new_pack.JEchYy/_new  2019-05-22 11:00:13.622751134 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package azure-cli-feedback
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           azure-cli-feedback
-Version:        2.1.4
+Version:        2.2.0
 Release:        0
 Summary:        Microsoft Azure CLI 'feedback' Command Module
 License:        MIT
@@ -27,15 +27,14 @@
 Source1:        LICENSE.txt
 BuildRequires:  azure-cli-command-modules-nspkg
 BuildRequires:  azure-cli-nspkg
-BuildRequires:  python3-azure-nspkg
-BuildRequires:  python3-devel
+BuildRequires:  fdupes
+BuildRequires:  python3-azure-nspkg >= 3.0.0
 BuildRequires:  python3-setuptools
-BuildRequires:  unzip
 Requires:       azure-cli-command-modules-nspkg
 Requires:       azure-cli-core
 Requires:       azure-cli-nspkg
 Requires:       python3-applicationinsights
-Requires:       python3-azure-nspkg
+Requires:       python3-azure-nspkg >= 3.0.0
 Conflicts:      azure-cli < 2.0.0
 
 BuildArch:      noarch
@@ -55,6 +54,7 @@
 
 %install
 python3 setup.py install --root=%{buildroot} --prefix=%{_prefix} 
--install-lib=%{python3_sitelib}
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
 rm -rf %{buildroot}%{python3_sitelib}/azure/cli/command_modules/__init__.*
 rm -rf %{buildroot}%{python3_sitelib}/azure/cli/command_modules/__pycache__
 rm -rf %{buildroot}%{python3_sitelib}/azure/cli/__init__.*

++++++ azure-cli-feedback-2.1.4.tar.gz -> azure-cli-feedback-2.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-feedback-2.1.4/HISTORY.rst 
new/azure-cli-feedback-2.2.0/HISTORY.rst
--- old/azure-cli-feedback-2.1.4/HISTORY.rst    2018-07-14 01:41:34.000000000 
+0200
+++ new/azure-cli-feedback-2.2.0/HISTORY.rst    2019-04-05 00:46:52.000000000 
+0200
@@ -3,6 +3,12 @@
 Release History
 ===============
 
+2.2.0
++++++
+* `az feedback` now shows metadata on recently run commands
+* `az feedback` prompts user to assist in issue creation process. Opens 
browser to issue url and copies auto-generated issue
+  text containing command and system related information to clipboard. Prints 
out issue body when run with '--verbose'
+
 2.1.4
 +++++
 * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-feedback-2.1.4/PKG-INFO 
new/azure-cli-feedback-2.2.0/PKG-INFO
--- old/azure-cli-feedback-2.1.4/PKG-INFO       2018-07-14 01:41:55.000000000 
+0200
+++ new/azure-cli-feedback-2.2.0/PKG-INFO       2019-04-05 00:47:37.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: azure-cli-feedback
-Version: 2.1.4
+Version: 2.2.0
 Summary: Microsoft Azure Command-Line Tools Feedback Command Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -20,6 +20,12 @@
         Release History
         ===============
         
+        2.2.0
+        +++++
+        * `az feedback` now shows metadata on recently run commands
+        * `az feedback` prompts user to assist in issue creation process. 
Opens browser to issue url and copies auto-generated issue
+          text containing command and system related information to clipboard. 
Prints out issue body when run with '--verbose'
+        
         2.1.4
         +++++
         * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-feedback-2.1.4/azure/cli/command_modules/feedback/custom.py 
new/azure-cli-feedback-2.2.0/azure/cli/command_modules/feedback/custom.py
--- old/azure-cli-feedback-2.1.4/azure/cli/command_modules/feedback/custom.py   
2018-07-14 01:41:34.000000000 +0200
+++ new/azure-cli-feedback-2.2.0/azure/cli/command_modules/feedback/custom.py   
2019-04-05 00:46:52.000000000 +0200
@@ -4,61 +4,552 @@
 # 
--------------------------------------------------------------------------------------------
 
 from __future__ import print_function
-import sys
+import os
+import math
+import platform
+import datetime
+
+try:
+    from urllib.parse import urlencode  # python 3
+except ImportError:
+    from urllib import urlencode  # python 2
+
+from collections import namedtuple
 
 from knack.log import get_logger
 from knack.prompting import prompt, NoTTYException
 from knack.util import CLIError
 
-from azure.cli.core.util import COMPONENT_PREFIX, 
get_installed_cli_distributions
-from azure.cli.core.telemetry import set_feedback
+from azure.cli.core.util import get_az_version_string
+from azure.cli.core.azlogging import _UNKNOWN_COMMAND, _CMD_LOG_LINE_PREFIX
+from azure.cli.core.util import open_page_in_browser
+import pyperclip
+
+_ONE_MIN_IN_SECS = 60
+
+_ONE_HR_IN_SECS = 3600
+
 
 logger = get_logger(__name__)
 
-MSG_RATE = '\nHow likely is it you would recommend our Azure CLI to a friend 
or colleague? [0 to 10]: '
-MSG_INTR = 'We appreciate your feedback! This survey is only two questions and 
should take less than a minute.'
-MSG_BAD = '\nWhat changes would we have to make for you to give us a higher 
rating? '
-MSG_GOOD = '\nWhat do we do really well? '
-MSG_EMIL = '\nIf you would like to join our insiders program and receive tips, 
tricks, and early access to new ' \
-           'features, let us know by leaving your email address (leave blank 
to skip): '
-MSG_THNK = '\nThanks for your feedback!'
+_MSG_THNK = 'Thanks for your feedback!'
+
+_GET_STARTED_URL = "aka.ms/azcli/get-started"
+_QUESTIONS_URL = "aka.ms/azcli/questions"
+_CLI_ISSUES_URL = "aka.ms/azcli/issues"
+_EXTENSIONS_ISSUES_URL = "aka.ms/azcli/ext/issues"
+
+_MSG_INTR = \
+    '\nWe appreciate your feedback!\n\n' \
+    'For more information on getting started, visit: {}\n' \
+    'If you have questions, visit our Stack Overflow page: {}\n'\
+    .format(_GET_STARTED_URL, _QUESTIONS_URL)
+
+_MSG_CMD_ISSUE = "\nEnter the number of the command you would like to create 
an issue for. Enter q to quit: "
+
+_MSG_ISSUE = "Would you like to create an issue? Enter Y or N: "
+
+_ISSUES_TEMPLATE_PREFIX = """
+
+BEGIN TEMPLATE
+===============
+**A browser has been opened to {} to create an issue.**
+**The issue template has been copied to your clipboard. You can also run `az 
feedback --verbose` to emit the output to stdout.**
+"""
+
+_ISSUES_TEMPLATE = """
+
+### **This is an autogenerated template. Please review and update as needed.**
+
+## Describe the bug
+
+**Command Name**
+`{command_name}`
+
+**Errors:**
+{errors_string}
+
+## To Reproduce:
+Steps to reproduce the behavior. Note: Command arguments have been redacted.
+
+- `Fill in additional info here`
+- `Run: {executed_command}`
+
+## Expected Behavior
+
+A clear and concise description of what you expected to happen.
+
+## Environment Summary
+```
+{platform}
+{python_info}
+{shell}
+
+{cli_version}
+```
+## Additional Context
+Add any other context about the problem here.
+
+<!-- Please do not remove these markdown comments -->
+{auto_gen_comment}
+
+"""
+
+_AUTO_GEN_COMMENT = "<!--auto-generated-->"
+
+_LogMetadataType = namedtuple('LogMetadata', ['cmd', 'seconds_ago', 
'file_path', 'p_id'])
+
+
+class CommandLogFile(object):
+    _LogRecordType = namedtuple("LogRecord", ["p_id", "date_time", "level", 
"logger", "log_msg"])
+    UNKNOWN_CMD = "Unknown"
+
+    def __init__(self, log_file_path, time_now=None):
+
+        if (time_now is not None) and (not isinstance(time_now, 
datetime.datetime)):
+            raise TypeError("Expected type {} for time_now, instead received 
{}.".format(datetime.datetime, type(time_now)))  # pylint: disable=line-too-long
+
+        if not os.path.isfile(log_file_path):
+            raise ValueError("File {} is not an existing 
file.".format(log_file_path))
+
+        self._command_name = None
+        self._log_file_path = log_file_path
+
+        if time_now is None:
+            self._time_now = datetime.datetime.now()
+        else:
+            self._time_now = time_now
+
+        self._metadata = self._get_command_metadata_from_file()
+        self._data = None
+
+    @property
+    def metadata_tup(self):
+        return self._metadata
+
+    @property
+    def command_data_dict(self):
+        if not self._data:
+            self._data = self._get_command_data_from_metadata()
+        return self._data
 
+    def get_command_name_str(self):
+        if self._command_name is not None:
+            return self._command_name  # attempt to return cached command name
+
+        if not self.metadata_tup:
+            return ""
+
+        args = self.command_data_dict.get("command_args", "")
+
+        if self.metadata_tup.cmd != self.UNKNOWN_CMD:
+            self._command_name = self.metadata_tup.cmd
+
+            if "-h" in args or "--help" in args:
+                self._command_name += " --help"
+        else:
+            self._command_name = self.UNKNOWN_CMD
+            if args:
+                command_args = args if len(args) < 16 else args[:11] + " ..."
+                command_args = command_args.replace("=", "").replace("{", 
"").replace("}", "")
+                self._command_name = "{} ({}) ".format(self._command_name, 
command_args)
+
+        return self._command_name
+
+    def get_command_status(self):
+        if not self.command_data_dict:
+            return ""
+
+        was_successful = self.command_data_dict.get("success", None)
+        if was_successful is None:
+            success_msg = "RUNNING"
+        else:
+            success_msg = "SUCCESS" if was_successful else "FAILURE"
+        return success_msg
+
+    def get_command_time_str(self):
+        if not self.metadata_tup:
+            return ""
+
+        total_seconds = self.metadata_tup.seconds_ago
+
+        time_delta = datetime.timedelta(seconds=total_seconds)
+        logger.debug("%s time_delta", time_delta)
+
+        if time_delta.days > 0:
+            time_str = "Ran: {} days ago".format(time_delta.days)
+        elif total_seconds > _ONE_HR_IN_SECS:
+            hrs, secs = divmod(total_seconds, _ONE_HR_IN_SECS)
+            logger.debug("%s hrs, %s secs", hrs, secs)
+            hrs = int(hrs)
+            mins = math.floor(secs / _ONE_MIN_IN_SECS)
+            time_str = "Ran: {} hrs {:02} mins ago".format(hrs, mins)
+        elif total_seconds > _ONE_MIN_IN_SECS:
+            time_str = "Ran: {} mins ago".format(math.floor(total_seconds / 
_ONE_MIN_IN_SECS))
+        else:
+            time_str = "Ran: {} secs ago".format(math.floor(total_seconds))
+
+        return time_str
+
+    def _get_command_metadata_from_file(self):
+        if not self._log_file_path:
+            return None
+
+        time_now = datetime.datetime.now() if not self._time_now else 
self._time_now
 
-def _prompt_net_promoter_score():
-    score = -1
-    help_string = 'Please rate between 0 and 10'
-    while score < 0 or score > 10:
         try:
-            score = int(prompt(MSG_RATE, help_string=help_string))
-        except ValueError:
-            logger.warning(help_string)
+            _, file_name = os.path.split(self._log_file_path)
+            poss_date, poss_time, poss_command, poss_pid, _ = 
file_name.split(".")
+            date_time_stamp = 
datetime.datetime.strptime("{}-{}".format(poss_date, poss_time), 
"%Y-%m-%d-%H-%M-%S")
+            command = "az " + poss_command.replace("_", " ") if poss_command 
!= _UNKNOWN_COMMAND else self.UNKNOWN_CMD  # pylint: disable=line-too-long
+        except ValueError as e:
+            logger.debug("Could not load metadata from file name %s.", 
self._log_file_path)
+            logger.debug(e)
+            return None
+
+        difference = time_now - date_time_stamp
+
+        total_seconds = difference.total_seconds()
+
+        return _LogMetadataType(cmd=command, seconds_ago=total_seconds, 
file_path=self._log_file_path, p_id=int(poss_pid))  # pylint: 
disable=line-too-long
+
+    def _get_command_data_from_metadata(self):  # pylint: 
disable=too-many-statements
+        def _get_log_record_list(log_fp, p_id):
+            """
+             Get list of records / messages in the log file
+            :param log_fp: log file object
+            :param p_id: process id of command
+            :return:
+            """
+            prev_record = None
+            log_record_list = []
+            for line in log_fp:
+                # attempt to extract log data
+                log_record = CommandLogFile._get_info_from_log_line(line, p_id)
+
+                if log_record:  # if new record parsed, add old record to the 
list
+                    if prev_record:
+                        log_record_list.append(prev_record)
+                    prev_record = log_record
+                elif prev_record:  # otherwise this is a continuation of a log 
record, add to prev record
+                    new_log_msg = prev_record.log_msg + line
+                    prev_record = 
CommandLogFile._LogRecordType(p_id=prev_record.p_id, 
date_time=prev_record.date_time,
+                                                                # pylint: 
disable=line-too-long
+                                                                
level=prev_record.level, logger=prev_record.logger,
+                                                                
log_msg=new_log_msg)
+            if prev_record:
+                log_record_list.append(prev_record)
+            return log_record_list
+
+        if not self.metadata_tup:
+            return {}
 
-    return score
+        _EXT_NAME_PREFIX = "extension name:"
+        _EXT_VERS_PREFIX = "extension version:"
 
+        file_name = self.metadata_tup.file_path
+        p_id = self.metadata_tup.p_id
+
+        try:
+            with open(file_name, 'r') as log_fp:
+                log_record_list = _get_log_record_list(log_fp, p_id)
+        except IOError:
+            logger.debug("Failed to open command log file %s", file_name)
+            return {}
+
+        if not log_record_list:
+            logger.debug("No command log messages found in file %s", file_name)
+            return {}
+
+        log_data = {}
+        # 1. Figure out whether the command was successful or not. Last log 
record should be the exit code
+        try:
+            status_msg = log_record_list[-1].log_msg.strip()
+            if status_msg.startswith("exit code"):
+                idx = status_msg.index(":")  # raises ValueError
+                exit_code = int(log_record_list[-1].log_msg[idx + 1:].strip())
+                log_data["success"] = True if not exit_code else False
+        except (IndexError, ValueError):
+            logger.debug("Couldn't extract exit code from command log %s.", 
file_name)
+
+        # 2. If there are any errors, this is a failed command. Log the errors
+        # 3. Also get extension information.
+        for record in log_record_list:
+            errors = log_data.setdefault("errors", [])  # log_data["errors"]
+            if record.level.lower() == "error":
+                log_data["success"] = False
+                errors.append(record.log_msg)
+
+            poss_ext_msg = record.log_msg.strip()
+            if record.level.lower() == "info":
+                if poss_ext_msg.startswith(_EXT_NAME_PREFIX):
+                    log_data["extension_name"] = 
poss_ext_msg[len(_EXT_NAME_PREFIX):].strip()
+                elif poss_ext_msg.startswith(_EXT_VERS_PREFIX):
+                    log_data["extension_version"] = 
poss_ext_msg[len(_EXT_VERS_PREFIX):].strip()
+
+        # 4. Get command args string. from first record
+        try:
+            command_args_msg = log_record_list[0].log_msg.strip()
+            if command_args_msg.lower().startswith("command args:"):
+                idx = command_args_msg.index(":")
+                log_data["command_args"] = command_args_msg[idx + 1:].strip()
+            else:
+                raise ValueError
+        except (IndexError, ValueError):
+            logger.debug("Couldn't get command args from command log %s.", 
file_name)
+
+        return log_data
+
+    @staticmethod
+    def _get_info_from_log_line(line, p_id):
+        """
+
+        Extract log line information based on the following command log format 
in azlogging.py
+
+        lfmt = logging.Formatter('%(process)d | %(created)s | %(levelname)s | 
%(name)s | %(message)s')
+
+        :param line: the line from the log file.
+        :return: returned parsed line information or None
+        """
+
+        if not line.startswith(_CMD_LOG_LINE_PREFIX):
+            return None
+
+        line = line[len(_CMD_LOG_LINE_PREFIX):]
+        parts = line.split("|", 4)
+
+        if len(parts) != 5:  # there must be 5 items
+            return None
+
+        for i, part in enumerate(parts):
+            parts[i] = part.strip()
+            if i == 0:
+                parts[0] = int(parts[0])
+                if parts[0] != p_id:  # ensure that this is indeed a valid log.
+                    return None
+
+        return CommandLogFile._LogRecordType(*parts)
+
+
+def _build_issue_info_tup(command_log_file=None):
+    def _get_parent_proc_name():
+        import psutil
+        parent = psutil.Process(os.getpid()).parent()
+        if parent:
+            #  powershell.exe launches cmd.exe to launch the cli.
+            grandparent = parent.parent()
+            if grandparent and 
grandparent.name().lower().startswith("powershell"):
+                return grandparent.name()
+            # if powershell is not the grandparent, simply return the parent's 
name.
+            return parent.name()
+        return None
+
+    format_dict = {"command_name": "", "errors_string": "",
+                   "executed_command": ""}
+
+    is_ext = False
+    # Get command information, if applicable
+    if command_log_file:
+        command_name = command_log_file.metadata_tup.cmd
+        format_dict["command_name"] = command_name
+
+        if command_log_file.command_data_dict:
+            errors = 
"\n".join(command_log_file.command_data_dict.get("errors", []))
+            executed_command = 
command_log_file.command_data_dict.get("command_args", "")
+            extension_name = 
command_log_file.command_data_dict.get("extension_name", "")
+            extension_version = 
command_log_file.command_data_dict.get("extension_version", "")
+
+            extension_info = ""
+            if extension_name:
+                extension_info = "\nExtension Name: {}. Version: 
{}.".format(extension_name, extension_version)
+                is_ext = True
+
+            if errors:
+                num_lines = errors.count("\n")
+                reaction = ":confused:"
+                if num_lines >= 100:
+                    reaction = ":expressionless:"
+                elif num_lines >= 15:
+                    reaction = ":open_mouth:"
+                errors = "\n{}\n\n```{}```".format(reaction, errors)
+
+            format_dict["errors_string"] = errors
+            format_dict["executed_command"] = "az " + executed_command if 
executed_command else executed_command
+            format_dict["command_name"] += extension_info
+
+    # Get other system information
+    format_dict["cli_version"] = _get_az_version_summary()
+    format_dict["python_info"] = "Python {}".format(platform.python_version())
+    format_dict["platform"] = "{}".format(platform.platform())
+    format_dict["shell"] = "Shell: {}".format(_get_parent_proc_name())
+    format_dict["auto_gen_comment"] = _AUTO_GEN_COMMENT
+
+    issues_url = _EXTENSIONS_ISSUES_URL if is_ext else _CLI_ISSUES_URL
+
+    # prefix formatted url with 'https://' if necessary and supply empty body 
to remove any existing issue template
+    formatted_issues_url = issues_url
+    if not formatted_issues_url.startswith("http"):
+        formatted_issues_url = "https://"; + formatted_issues_url
+    new_placeholder = urlencode({'body': "The issue has been copied to your 
clipboard. Paste it here!"
+                                         "\nTo print out the issue body 
locally, run `az feedback --verbose`"})
+    formatted_issues_url = "{}?{}".format(formatted_issues_url, 
new_placeholder)
+
+    return _ISSUES_TEMPLATE_PREFIX.format(issues_url), 
_ISSUES_TEMPLATE.format(**format_dict), formatted_issues_url
+
+
+def _get_az_version_summary():
+    """
+    This depends on get_az_version_string not being changed, add some tests to 
make this and other methods more robust.
+    :return: az version info
+    """
+    az_vers_string = get_az_version_string()[0]
+
+    lines = az_vers_string.splitlines()
+
+    new_lines = []
+    ext_line = -1
+    legal_line = -1
+    for i, line in enumerate(lines):
+        if line.startswith("azure-cli"):
+            new_lines.append(line)
+        if line.lower().startswith("extensions:"):
+            ext_line = i
+            continue
+        l_lower = line.lower()
+        if all(["legal" in l_lower, "docs" in l_lower, "info" in l_lower]):
+            legal_line = i
+            break
+
+    new_lines.append("")
+
+    if 0 < ext_line < legal_line:
+        for i in range(ext_line, legal_line):
+            new_lines.append(lines[i])
+
+    return "\n".join(new_lines)
+
+
+def _get_command_log_files(cli_ctx, time_now=None):
+    command_logs_dir = cli_ctx.logging.get_command_log_dir()
+    files = os.listdir(command_logs_dir)
+    files = (file_name for file_name in files if file_name.endswith(".log"))
+    files = sorted(files)
+    command_log_files = []
+    for file_name in files:
+        file_path = os.path.join(command_logs_dir, file_name)
+        cmd_log_file = CommandLogFile(file_path, time_now)
+
+        if cmd_log_file.metadata_tup:
+            command_log_files.append(cmd_log_file)
+        else:
+            logger.debug("%s is an invalid command log file.", file_path)
+    return command_log_files
+
+
+def _display_recent_commands(cmd):
+    def _pad_string(my_str, pad_len):
+        while len(my_str) < pad_len:
+            my_str += " "
+        return my_str
+
+    time_now = datetime.datetime.now()
+
+    command_log_files = _get_command_log_files(cmd.cli_ctx, time_now)
+
+    # if no command log files, return
+    if not command_log_files:
+        return []
+
+    command_log_files = command_log_files[-9:]
+
+    max_len_dict = dict(name_len=0, success_len=0, time_len=0)
+
+    for log_file in command_log_files:
+        max_len_dict["name_len"] = max(len(log_file.get_command_name_str()), 
max_len_dict["name_len"])
+        max_len_dict["success_len"] = max(len(log_file.get_command_status()), 
max_len_dict["success_len"])
+        max_len_dict["time_len"] = max(len(log_file.get_command_time_str()), 
max_len_dict["time_len"])
+
+    print("Recent commands:\n")
+    command_log_files = [None] + command_log_files
+    for i, log_info in enumerate(command_log_files):
+        if log_info is None:
+            print("   [{}] {}".format(i, "create a generic issue."))
+        else:
+            cmd_name = _pad_string(log_info.get_command_name_str(), 
max_len_dict["name_len"])
+            success_msg = _pad_string(log_info.get_command_status() + ".", 
max_len_dict["success_len"] + 1)
+            time_msg = _pad_string(log_info.get_command_time_str() + ".", 
max_len_dict["time_len"] + 1)
+            print("   [{}] {}: {} {}".format(i, cmd_name, success_msg, 
time_msg))
+
+    return command_log_files
+
+
+def _prompt_issue(recent_command_list):
+    if recent_command_list:
+        max_idx = len(recent_command_list) - 1
+        ans = -1
+        help_string = 'Please choose between 0 and {}, or enter q to quit: 
'.format(max_idx)
+
+        while ans < 0 or ans > max_idx:
+            try:
+                ans = prompt(_MSG_CMD_ISSUE.format(max_idx), 
help_string=help_string)
+                if ans.lower() in ["q", "quit"]:
+                    ans = ans.lower()
+                    break
+                ans = int(ans)
+            except ValueError:
+                logger.warning(help_string)
+                ans = -1
+
+    else:
+        ans = None
+        help_string = 'Please choose between Y and N: '
+
+        while not ans:
+            ans = prompt(_MSG_ISSUE, help_string=help_string)
+            if ans.lower() not in ["y", "n", "yes", "no", "q"]:
+                ans = None
+                continue
+
+            # strip to short form
+            ans = ans[0].lower() if ans else None
+
+    if ans in ["y", "n"]:
+        if ans == "y":
+            prefix, body, url = _build_issue_info_tup()
+        else:
+            return False
+    else:
+        if ans in ["q", "quit"]:
+            return False
+        if ans == 0:
+            prefix, body, url = _build_issue_info_tup()
+        else:
+            prefix, body, url = _build_issue_info_tup(recent_command_list[ans])
+
+    print(prefix)
+
+    # open issues page in browser and copy issue body to clipboard
+    try:
+        pyperclip.copy(body)
+    except pyperclip.PyperclipException as ex:
+        logger.debug(ex)
 
-def _get_version_info():
-    installed_dists = get_installed_cli_distributions()
+    logger.info(body)
+    open_page_in_browser(url)
 
-    component_version_info = sorted([{'name': 
dist.key.replace(COMPONENT_PREFIX, ''),
-                                      'version': dist.version}
-                                     for dist in installed_dists
-                                     if dist.key.startswith(COMPONENT_PREFIX)],
-                                    key=lambda x: x['name'])
-    return str(component_version_info), sys.version
+    return True
 
 
-def handle_feedback():
+def handle_feedback(cmd):
     try:
-        print(MSG_INTR)
-        score = _prompt_net_promoter_score()
-        if score == 10:
-            suggestion = prompt(MSG_GOOD)
-        else:
-            suggestion = prompt(MSG_BAD)
-        email_address = prompt(MSG_EMIL)
-        set_feedback('[{}]{}[{}]'.format(score, suggestion, email_address))
-        print(MSG_THNK)
+        print(_MSG_INTR)
+        recent_commands = _display_recent_commands(cmd)
+        res = _prompt_issue(recent_commands)
+
+        if res:
+            print(_MSG_THNK)
+        return
     except NoTTYException:
-        raise CLIError('This command is interactive and no tty available.')
+        raise CLIError('This command is interactive, however no tty is 
available.')
     except (EOFError, KeyboardInterrupt):
         print()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-feedback-2.1.4/azure_cli_feedback.egg-info/PKG-INFO 
new/azure-cli-feedback-2.2.0/azure_cli_feedback.egg-info/PKG-INFO
--- old/azure-cli-feedback-2.1.4/azure_cli_feedback.egg-info/PKG-INFO   
2018-07-14 01:41:55.000000000 +0200
+++ new/azure-cli-feedback-2.2.0/azure_cli_feedback.egg-info/PKG-INFO   
2019-04-05 00:47:37.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: azure-cli-feedback
-Version: 2.1.4
+Version: 2.2.0
 Summary: Microsoft Azure Command-Line Tools Feedback Command Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -20,6 +20,12 @@
         Release History
         ===============
         
+        2.2.0
+        +++++
+        * `az feedback` now shows metadata on recently run commands
+        * `az feedback` prompts user to assist in issue creation process. 
Opens browser to issue url and copies auto-generated issue
+          text containing command and system related information to clipboard. 
Prints out issue body when run with '--verbose'
+        
         2.1.4
         +++++
         * Minor fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-feedback-2.1.4/azure_cli_feedback.egg-info/requires.txt 
new/azure-cli-feedback-2.2.0/azure_cli_feedback.egg-info/requires.txt
--- old/azure-cli-feedback-2.1.4/azure_cli_feedback.egg-info/requires.txt       
2018-07-14 01:41:55.000000000 +0200
+++ new/azure-cli-feedback-2.2.0/azure_cli_feedback.egg-info/requires.txt       
2019-04-05 00:47:37.000000000 +0200
@@ -1,2 +1 @@
-applicationinsights
 azure-cli-core
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-feedback-2.1.4/setup.py 
new/azure-cli-feedback-2.2.0/setup.py
--- old/azure-cli-feedback-2.1.4/setup.py       2018-07-14 01:41:34.000000000 
+0200
+++ new/azure-cli-feedback-2.2.0/setup.py       2019-04-05 00:46:52.000000000 
+0200
@@ -15,7 +15,7 @@
     cmdclass = {}
 
 
-VERSION = "2.1.4"
+VERSION = "2.2.0"
 CLASSIFIERS = [
     'Development Status :: 5 - Production/Stable',
     'Intended Audience :: Developers',
@@ -31,7 +31,6 @@
 ]
 
 DEPENDENCIES = [
-    'applicationinsights',
     'azure-cli-core',
 ]
 


Reply via email to