Hello community,

here is the log from the commit of package azure-cli-core for openSUSE:Factory 
checked in at 2020-05-08 23:06:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/azure-cli-core (Old)
 and      /work/SRC/openSUSE:Factory/.azure-cli-core.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "azure-cli-core"

Fri May  8 23:06:24 2020 rev:14 rq:801209 version:2.5.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/azure-cli-core/azure-cli-core.changes    
2020-05-03 22:45:59.471002910 +0200
+++ /work/SRC/openSUSE:Factory/.azure-cli-core.new.2738/azure-cli-core.changes  
2020-05-08 23:06:30.922004879 +0200
@@ -1,0 +2,9 @@
+Thu May  7 07:46:57 UTC 2020 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- New upstream release
+  + Version 2.5.1
+  + For detailed information about changes see the
+    HISTORY.txt file provided with this package
+- Update Requires from setup.py
+
+-------------------------------------------------------------------

Old:
----
  azure-cli-core-2.3.1.tar.gz

New:
----
  azure-cli-core-2.5.1.tar.gz

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

Other differences:
------------------
++++++ azure-cli-core.spec ++++++
--- /var/tmp/diff_new_pack.clQA0g/_old  2020-05-08 23:06:31.466005991 +0200
+++ /var/tmp/diff_new_pack.clQA0g/_new  2020-05-08 23:06:31.466005991 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           azure-cli-core
-Version:        2.3.1
+Version:        2.5.1
 Release:        0
 Summary:        Microsoft Azure CLI Core Module
 License:        MIT
@@ -40,21 +40,25 @@
 Requires:       python3-adal >= 1.2
 Requires:       python3-argcomplete < 2.0
 Requires:       python3-argcomplete >= 1.8
-Requires:       python3-azure-mgmt-resource < 9.0.0
-Requires:       python3-azure-mgmt-resource >= 8.0.1
+Requires:       python3-azure-mgmt-core < 2.0.0
+Requires:       python3-azure-mgmt-core >= 1.0.0
+Requires:       python3-azure-mgmt-resource < 10.0.0
+Requires:       python3-azure-mgmt-resource >= 9.0.0
 Requires:       python3-azure-nspkg >= 3.0.0
 Requires:       python3-colorama >= 0.3.9
 Requires:       python3-humanfriendly < 9.0
 Requires:       python3-humanfriendly >= 4.7
 Requires:       python3-jmespath
 Requires:       python3-knack < 1.0.0
-Requires:       python3-knack >= 0.7.0~rc1
+Requires:       python3-knack >= 0.7.0~rc4
+Requires:       python3-msal < 2.0.0
+Requires:       python3-msal >= 1.0.0
 Requires:       python3-msrest >= 0.4.4
-Requires:       python3-msrestazure >= 0.6.2
+Requires:       python3-msrestazure >= 0.6.3
 Requires:       python3-paramiko < 3.0.0
-Requires:       python3-paramiko >= 2.0.
+Requires:       python3-paramiko >= 2.0.8
 Requires:       python3-pip
-Requires:       python3-pkginfo
+Requires:       python3-pkginfo >= 1.5.0.1
 Requires:       python3-pyOpenSSL >= 17.1.0
 Requires:       python3-requests < 3.0.0
 Requires:       python3-requests >= 2.20

++++++ azure-cli-core-2.3.1.tar.gz -> azure-cli-core-2.5.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/HISTORY.rst 
new/azure-cli-core-2.5.1/HISTORY.rst
--- old/azure-cli-core-2.3.1/HISTORY.rst        2020-04-01 09:16:17.000000000 
+0200
+++ new/azure-cli-core-2.5.1/HISTORY.rst        2020-04-30 08:18:16.000000000 
+0200
@@ -3,6 +3,27 @@
 Release History
 ===============
 
+2.5.1
+++++++
+* Minor fixes
+
+2.5.0
+++++++
+* Fix logging file fd leaking (#13102)
+* Fix core tests failed under certain profiles (#13136)
+* Use pkginfo to query metadata for Python Package (#12782)
+
+2.4.0
+++++++
+* Upgrade msrestazure to 0.6.3 (#12839)
+* Output more error details of exceptions if possible (#12945)
+* Support track1 and track2 mgmt SDK side by side (#12952)
+* Fix generic remove property NoneType exception (#12950)
+* `az --version`: Show command instruction and detailed instruction link when 
updates available (#12981)
+* Fix bug in core test test_parser that will affect exception stack while 
existing if argument parse raise Exception
+* Make CLI respect file logging configuration option: enable_log_file and 
AZURE_LOGGING_ENABLE_LOG_FILE env variable
+* Fix the name of extension of dev type is None if it has incompatibility 
problem with core
+
 2.3.1
 ++++++
 * No changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/PKG-INFO 
new/azure-cli-core-2.5.1/PKG-INFO
--- old/azure-cli-core-2.3.1/PKG-INFO   2020-04-01 09:16:27.000000000 +0200
+++ new/azure-cli-core-2.5.1/PKG-INFO   2020-04-30 08:18:30.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: azure-cli-core
-Version: 2.3.1
+Version: 2.5.1
 Summary: Microsoft Azure Command-Line Tools Core Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -15,6 +15,27 @@
         Release History
         ===============
         
+        2.5.1
+        ++++++
+        * Minor fixes
+        
+        2.5.0
+        ++++++
+        * Fix logging file fd leaking (#13102)
+        * Fix core tests failed under certain profiles (#13136)
+        * Use pkginfo to query metadata for Python Package (#12782)
+        
+        2.4.0
+        ++++++
+        * Upgrade msrestazure to 0.6.3 (#12839)
+        * Output more error details of exceptions if possible (#12945)
+        * Support track1 and track2 mgmt SDK side by side (#12952)
+        * Fix generic remove property NoneType exception (#12950)
+        * `az --version`: Show command instruction and detailed instruction 
link when updates available (#12981)
+        * Fix bug in core test test_parser that will affect exception stack 
while existing if argument parse raise Exception
+        * Make CLI respect file logging configuration option: enable_log_file 
and AZURE_LOGGING_ENABLE_LOG_FILE env variable
+        * Fix the name of extension of dev type is None if it has 
incompatibility problem with core
+        
         2.3.1
         ++++++
         * No changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/__init__.py 
new/azure-cli-core-2.5.1/azure/cli/core/__init__.py
--- old/azure-cli-core-2.3.1/azure/cli/core/__init__.py 2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/__init__.py 2020-04-30 
08:18:16.000000000 +0200
@@ -2,9 +2,11 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License. See License.txt in the project root for 
license information.
 # 
--------------------------------------------------------------------------------------------
+# pylint: disable=line-too-long
+
 from __future__ import print_function
 
-__version__ = "2.3.1"
+__version__ = "2.5.1"
 
 import os
 import sys
@@ -21,7 +23,7 @@
 from knack.experimental import ExperimentalItem
 from knack.util import CLIError
 from knack.arguments import ArgumentsContext, CaseInsensitiveList  # pylint: 
disable=unused-import
-from .local_context import AzCLILocalContext, STORE
+from .local_context import AzCLILocalContext, SET
 
 logger = get_logger(__name__)
 
@@ -29,6 +31,16 @@
                    'content_version', 'kwargs', 'client', 'no_wait']
 EVENT_FAILED_EXTENSION_LOAD = 'MainLoader.OnFailedExtensionLoad'
 
+_PACKAGE_UPGRADE_INSTRUCTIONS = {"YUM": ("sudo yum update -y azure-cli", 
"https://aka.ms/doc/UpdateAzureCliYum";),
+                                 "ZYPPER": ("sudo zypper refresh && sudo 
zypper update -y azure-cli", "https://aka.ms/doc/UpdateAzureCliZypper";),
+                                 "DEB": ("sudo apt-get update && sudo apt-get 
install --only-upgrade -y azure-cli", "https://aka.ms/doc/UpdateAzureCliApt";),
+                                 "HOMEBREW": ("brew update && brew upgrade 
azure-cli", "https://aka.ms/doc/UpdateAzureCliHomebrew";),
+                                 "PIP": ("curl -L 
https://aka.ms/InstallAzureCli | bash", 
"https://aka.ms/doc/UpdateAzureCliLinux";),
+                                 "MSI": 
("https://aka.ms/installazurecliwindows";, 
"https://aka.ms/doc/UpdateAzureCliMsi";),
+                                 "DOCKER": ("docker pull 
mcr.microsoft.com/azure-cli", "https://aka.ms/doc/UpdateAzureCliDocker";)}
+
+_GENERAL_UPGRADE_INSTRUCTION = 'Instructions can be found at 
https://aka.ms/doc/InstallAzureCli'
+
 
 class AzCli(CLI):
 
@@ -89,20 +101,50 @@
 
     def show_version(self):
         from azure.cli.core.util import get_az_version_string
-        from azure.cli.core.commands.constants import SURVEY_PROMPT, 
SURVEY_PROMPT_COLOR
+        from azure.cli.core.commands.constants import (SURVEY_PROMPT, 
SURVEY_PROMPT_COLOR,
+                                                       UX_SURVEY_PROMPT, 
UX_SURVEY_PROMPT_COLOR)
 
         ver_string, updates_available = get_az_version_string()
         print(ver_string)
         if updates_available == -1:
             logger.warning('Unable to check if your CLI is up-to-date. Check 
your internet connection.')
         elif updates_available:
-            logger.warning('You have %i updates available. Consider updating 
your CLI installation. '
-                           'Instructions can be found at 
https://docs.microsoft.com/en-us/cli/azure/install-azure-cli',
-                           updates_available)
+            warning_msg = 'You have %i updates available. Consider updating 
your CLI installation'
+            from azure.cli.core._environment import _ENV_AZ_INSTALLER
+            installer = os.getenv(_ENV_AZ_INSTALLER)
+            instruction_msg = ''
+            if installer in _PACKAGE_UPGRADE_INSTRUCTIONS:
+                if installer == 'RPM':
+                    from azure.cli.core.util import get_linux_distro
+                    distname, _ = get_linux_distro()
+                    if not distname:
+                        instruction_msg = '. 
{}'.format(_GENERAL_UPGRADE_INSTRUCTION)
+                    else:
+                        distname = distname.lower().strip()
+                        if any(x in distname for x in ['centos', 'rhel', 'red 
hat', 'fedora']):
+                            installer = 'YUM'
+                        elif any(x in distname for x in ['opensuse', 'suse', 
'sles']):
+                            installer = 'ZYPPER'
+                        else:
+                            instruction_msg = '. 
{}'.format(_GENERAL_UPGRADE_INSTRUCTION)
+                elif installer == 'PIP':
+                    import platform
+                    system = platform.system()
+                    alternative_command = " or '{}' if you used our script for 
installation. Detailed instructions can be found at 
{}".format(_PACKAGE_UPGRADE_INSTRUCTIONS[installer][0], 
_PACKAGE_UPGRADE_INSTRUCTIONS[installer][1]) if system != 'Windows' else ''
+                    instruction_msg = " with 'pip install --upgrade 
azure-cli'{}".format(alternative_command)
+                if instruction_msg:
+                    warning_msg += instruction_msg
+                else:
+                    warning_msg += " with '{}'. Detailed instructions can be 
found at {}".format(_PACKAGE_UPGRADE_INSTRUCTIONS[installer][0], 
_PACKAGE_UPGRADE_INSTRUCTIONS[installer][1])
+            else:
+                warning_msg += '. {}'.format(_GENERAL_UPGRADE_INSTRUCTION)
+            logger.warning(warning_msg, updates_available)
         else:
             print('Your CLI is up-to-date.')
-
-        print('\n' + (SURVEY_PROMPT_COLOR if self.enable_color else 
SURVEY_PROMPT))
+        show_link = self.config.getboolean('output', 'show_survey_link', True)
+        if show_link:
+            print('\n' + (SURVEY_PROMPT_COLOR if self.enable_color else 
SURVEY_PROMPT))
+            print(UX_SURVEY_PROMPT_COLOR if self.enable_color else 
UX_SURVEY_PROMPT)
 
     def exception_handler(self, ex):  # pylint: disable=no-self-use
         from azure.cli.core.util import handle_exception
@@ -111,7 +153,7 @@
     def save_local_context(self, parsed_args, argument_definitions, 
specified_arguments):
         """ Local Context Attribute arguments
 
-        Save argument value to local context if it is defined as STORE and 
user specify a value for it.
+        Save argument value to local context if it is defined as SET and user 
specify a value for it.
 
         :param parsed_args: Parsed args which return by AzCliCommandParser 
parse_args
         :type parsed_args: Namespace
@@ -122,12 +164,12 @@
         """
 
         for argument_name in specified_arguments:
-            # make sure STORE is defined
+            # make sure SET is defined
             if argument_name not in argument_definitions:
                 continue
             argtype = argument_definitions[argument_name].type
             lca = argtype.settings.get('local_context_attribute', None)
-            if not lca or not lca.actions or STORE not in lca.actions:
+            if not lca or not lca.actions or SET not in lca.actions:
                 continue
             # get the specified value
             value = getattr(parsed_args, argument_name)
@@ -228,6 +270,7 @@
                         continue
                     ext_name = ext.name
                     ext_dir = ext.path or get_extension_path(ext_name)
+                    logger.debug("Extensions directory: '%s'", ext_dir)
                     sys.path.append(ext_dir)
                     try:
                         ext_mod = get_extension_modname(ext_name, 
ext_dir=ext_dir)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/_debug.py 
new/azure-cli-core-2.5.1/azure/cli/core/_debug.py
--- old/azure-cli-core-2.3.1/azure/cli/core/_debug.py   2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/_debug.py   2020-04-30 
08:18:16.000000000 +0200
@@ -31,6 +31,22 @@
     return client
 
 
+def change_ssl_cert_verification_track2():
+    client_kwargs = {}
+    if should_disable_connection_verify():
+        logger.warning("Connection verification disabled by environment 
variable %s",
+                       DISABLE_VERIFY_VARIABLE_NAME)
+        os.environ[ADAL_PYTHON_SSL_NO_VERIFY] = '1'
+        client_kwargs['connection_verify'] = False
+    elif REQUESTS_CA_BUNDLE in os.environ:
+        ca_bundle_file = os.environ[REQUESTS_CA_BUNDLE]
+        if not os.path.isfile(ca_bundle_file):
+            raise CLIError('REQUESTS_CA_BUNDLE environment variable is 
specified with an invalid file path')
+        logger.debug("Using CA bundle file at '%s'.", ca_bundle_file)
+        client_kwargs['connection_verify'] = ca_bundle_file
+    return client_kwargs
+
+
 def allow_debug_adal_connection():
     if should_disable_connection_verify():
         os.environ[ADAL_PYTHON_SSL_NO_VERIFY] = '1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/_environment.py 
new/azure-cli-core-2.5.1/azure/cli/core/_environment.py
--- old/azure-cli-core-2.3.1/azure/cli/core/_environment.py     2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/_environment.py     2020-04-30 
08:18:16.000000000 +0200
@@ -4,6 +4,9 @@
 # 
--------------------------------------------------------------------------------------------
 
 
+_ENV_AZ_INSTALLER = 'AZ_INSTALLER'
+
+
 def get_config_dir():
     import os
     return os.getenv('AZURE_CONFIG_DIR', None) or 
os.path.expanduser(os.path.join('~', '.azure'))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/_help.py 
new/azure-cli-core-2.5.1/azure/cli/core/_help.py
--- old/azure-cli-core-2.3.1/azure/cli/core/_help.py    2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/_help.py    2020-04-30 
08:18:16.000000000 +0200
@@ -7,7 +7,8 @@
 import argparse
 
 from azure.cli.core.commands import ExtensionCommandSource
-from azure.cli.core.commands.constants import SURVEY_PROMPT, 
SURVEY_PROMPT_COLOR
+from azure.cli.core.commands.constants import (SURVEY_PROMPT, 
SURVEY_PROMPT_COLOR,
+                                               UX_SURVEY_PROMPT, 
UX_SURVEY_PROMPT_COLOR)
 
 from knack.help import (HelpFile as KnackHelpFile, CommandHelpFile as 
KnackCommandHelpFile,
                         GroupHelpFile as KnackGroupHelpFile, 
ArgumentGroupRegistry as KnackArgumentGroupRegistry,
@@ -172,8 +173,11 @@
         else:
             AzCliHelp.update_examples(help_file)
         self._print_detailed_help(cli_name, help_file)
-
-        print(SURVEY_PROMPT_COLOR if self.cli_ctx.enable_color else 
SURVEY_PROMPT)
+        show_link = self.cli_ctx.config.getboolean('output', 
'show_survey_link', True)
+        if show_link:
+            print(SURVEY_PROMPT_COLOR if self.cli_ctx.enable_color else 
SURVEY_PROMPT)
+            if not nouns:
+                print(UX_SURVEY_PROMPT_COLOR if self.cli_ctx.enable_color else 
UX_SURVEY_PROMPT)
 
     def _register_help_loaders(self):
         import azure.cli.core._help_loaders as help_loaders
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/_msal.py 
new/azure-cli-core-2.5.1/azure/cli/core/_msal.py
--- old/azure-cli-core-2.3.1/azure/cli/core/_msal.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/azure-cli-core-2.5.1/azure/cli/core/_msal.py    2020-04-30 
08:18:16.000000000 +0200
@@ -0,0 +1,34 @@
+# 
--------------------------------------------------------------------------------------------
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for 
license information.
+# 
--------------------------------------------------------------------------------------------
+from knack.util import CLIError
+from msal import ClientApplication
+
+
+class AdalRefreshTokenBasedClientApplication(ClientApplication):
+    """
+    This is added only for vmssh feature.
+    It is a temporary solution and will deprecate after MSAL adopted 
completely.
+    """
+    def _acquire_token_silent_by_finding_rt_belongs_to_me_or_my_family(
+            self, authority, scopes, account, **kwargs):
+        # pylint: disable=line-too-long
+        return self._acquire_token_silent_by_finding_specific_refresh_token(
+            authority, scopes, None, **kwargs)
+
+    def _acquire_token_silent_by_finding_specific_refresh_token(
+            self, authority, scopes, query,
+            rt_remover=None, break_condition=lambda response: False, **kwargs):
+        refresh_token = kwargs.get('refresh_token', None)
+        client = self._build_client(self.client_credential, authority)
+        if 'refresh_token' in kwargs:
+            kwargs.pop('refresh_token')
+        if 'force_refresh' in kwargs:
+            kwargs.pop('force_refresh')
+        if 'correlation_id' in kwargs:
+            kwargs.pop('correlation_id')
+        response = client.obtain_token_by_refresh_token(refresh_token, 
scope=scopes, **kwargs)
+        if "error" in response:
+            raise CLIError(response["error"])
+        return response
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/_profile.py 
new/azure-cli-core-2.5.1/azure/cli/core/_profile.py
--- old/azure-cli-core-2.3.1/azure/cli/core/_profile.py 2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/_profile.py 2020-04-30 
08:18:16.000000000 +0200
@@ -593,6 +593,18 @@
                 str(account[_SUBSCRIPTION_ID]),
                 str(account[_TENANT_ID]))
 
+    def get_msal_token(self, scopes, data):
+        """
+        This is added only for vmssh feature.
+        It is a temporary solution and will deprecate after MSAL adopted 
completely.
+        """
+        account = self.get_subscription()
+        username = account[_USER_ENTITY][_USER_NAME]
+        tenant = account[_TENANT_ID] or 'common'
+        _, refresh_token, _, _ = self.get_refresh_token()
+        certificate = self._creds_cache.retrieve_msal_token(tenant, scopes, 
data, refresh_token)
+        return username, certificate
+
     def get_refresh_token(self, resource=None,
                           subscription=None):
         account = self.get_subscription(subscription)
@@ -1008,6 +1020,19 @@
             self.persist_cached_creds()
         return (token_entry[_TOKEN_ENTRY_TOKEN_TYPE], 
token_entry[_ACCESS_TOKEN], token_entry)
 
+    def retrieve_msal_token(self, tenant, scopes, data, refresh_token):
+        """
+        This is added only for vmssh feature.
+        It is a temporary solution and will deprecate after MSAL adopted 
completely.
+        """
+        from azure.cli.core._msal import AdalRefreshTokenBasedClientApplication
+        tenant = tenant or 'organizations'
+        authority = self._ctx.cloud.endpoints.active_directory + '/' + tenant
+        app = AdalRefreshTokenBasedClientApplication(_CLIENT_ID, 
authority=authority)
+        result = app.acquire_token_silent(scopes, None, data=data, 
refresh_token=refresh_token)
+
+        return result["access_token"]
+
     def retrieve_token_for_service_principal(self, sp_id, resource, tenant, 
use_cert_sn_issuer=False):
         self.load_adal_token_cache()
         matched = [x for x in self._service_principal_creds if sp_id == 
x[_SERVICE_PRINCIPAL_ID]]
@@ -1202,6 +1227,11 @@
             break
         except socket.error as ex:
             logger.warning("Port '%s' is taken with error '%s'. Trying with 
the next one", port, ex)
+        except UnicodeDecodeError:
+            logger.warning("Please make sure there is no international 
(Unicode) character in the computer name "
+                           r"or C:\Windows\System32\drivers\etc\hosts file's 
127.0.0.1 entries. "
+                           "For more details, please see 
https://github.com/Azure/azure-cli/issues/12957";)
+            break
 
     if reply_url is None:
         logger.warning("Error: can't reserve a port for authentication reply 
url")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/adal_authentication.py 
new/azure-cli-core-2.5.1/azure/cli/core/adal_authentication.py
--- old/azure-cli-core-2.3.1/azure/cli/core/adal_authentication.py      
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/adal_authentication.py      
2020-04-30 08:18:16.000000000 +0200
@@ -3,11 +3,12 @@
 # Licensed under the MIT License. See License.txt in the project root for 
license information.
 # 
--------------------------------------------------------------------------------------------
 
+import time
 import requests
 import adal
 
 from msrest.authentication import Authentication
-
+from azure.core.credentials import AccessToken
 from azure.cli.core.util import in_cloud_console
 
 from knack.util import CLIError
@@ -19,11 +20,10 @@
         self._token_retriever = token_retriever
         self._external_tenant_token_retriever = external_tenant_token_retriever
 
-    def signed_session(self, session=None):  # pylint: disable=arguments-differ
-        session = session or super(AdalAuthentication, self).signed_session()
+    def _get_token(self):
         external_tenant_tokens = None
         try:
-            scheme, token, _ = self._token_retriever()
+            scheme, token, full_token = self._token_retriever()
             if self._external_tenant_token_retriever:
                 external_tenant_tokens = 
self._external_tenant_token_retriever()
         except CLIError as err:
@@ -55,6 +55,20 @@
         except requests.exceptions.ConnectionError as err:
             raise CLIError('Please ensure you have network connection. Error 
detail: ' + str(err))
 
+        return scheme, token, full_token, external_tenant_tokens
+
+    # This method is exposed for Azure Core.
+    def get_token(self, *scopes, **kwargs):  # pylint:disable=unused-argument
+        _, token, full_token, _ = self._get_token()
+
+        return AccessToken(token, int(full_token['expiresIn'] + time.time()))
+
+    # This method is exposed for msrest.
+    def signed_session(self, session=None):  # pylint: disable=arguments-differ
+        session = session or super(AdalAuthentication, self).signed_session()
+
+        scheme, token, _, external_tenant_tokens = self._get_token()
+
         header = "{} {}".format(scheme, token)
         session.headers['Authorization'] = header
         if external_tenant_tokens:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/azlogging.py 
new/azure-cli-core-2.5.1/azure/cli/core/azlogging.py
--- old/azure-cli-core-2.3.1/azure/cli/core/azlogging.py        2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/azlogging.py        2020-04-30 
08:18:16.000000000 +0200
@@ -29,6 +29,7 @@
 
 from azure.cli.core.commands.events import EVENT_INVOKER_PRE_CMD_TBL_TRUNCATE
 
+from knack.events import EVENT_CLI_POST_EXECUTE
 from knack.log import CLILogging, get_logger
 from knack.util import ensure_dir
 
@@ -46,6 +47,7 @@
         self.command_logger_handler = None
         self.command_metadata_logger = None
         self.cli_ctx.register_event(EVENT_INVOKER_PRE_CMD_TBL_TRUNCATE, 
AzCliLogging.init_command_file_logging)
+        self.cli_ctx.register_event(EVENT_CLI_POST_EXECUTE, 
AzCliLogging.deinit_cmd_metadata_logging)
 
     def get_command_log_dir(self):
         return self.command_log_dir
@@ -77,10 +79,15 @@
 
             cmd_logger = 
logging.getLogger(AzCliLogging._COMMAND_METADATA_LOGGER)
 
-            self._init_command_logfile_handlers(cmd_logger, args)  # pylint: 
disable=protected-access
-            get_logger(__name__).debug("metadata file logging enabled - 
writing logs to '%s'.", self.command_log_dir)
+            # overwrite CLILogging._is_file_log_enabled() from knack
+            self.file_log_enabled = cli_ctx.config.getboolean('logging', 
'enable_log_file', fallback=True)
 
-            _delete_old_logs(self.command_log_dir)
+            if self.file_log_enabled:
+                self._init_command_logfile_handlers(cmd_logger, args)  # 
pylint: disable=protected-access
+                get_logger(__name__).debug("metadata file logging enabled - 
writing logs to '%s'.",
+                                           self.command_log_dir)
+
+                _delete_old_logs(self.command_log_dir)
 
     def _init_command_logfile_handlers(self, command_metadata_logger, args):
 
@@ -168,13 +175,18 @@
             self.command_metadata_logger.info("extension name: %s", 
extension_name)
             self.command_metadata_logger.info("extension version: %s", 
extension_version)
 
-    def end_cmd_metadata_logging(self, exit_code):
+    @staticmethod
+    def deinit_cmd_metadata_logging(cli_ctx):
+        cli_ctx.logging.end_cmd_metadata_logging(cli_ctx.result.exit_code if 
cli_ctx.result else 128)
+
+    def end_cmd_metadata_logging(self, exit_code):  # leave it non '-' prefix 
to not to break user
         if self.command_metadata_logger:
             self.command_metadata_logger.info("exit code: %s", exit_code)
 
             # We have finished metadata logging, remove handler and set 
command_metadata_handler to None.
             # crucial to remove handler as in python logger objects are shared 
which can affect testing of this logger
             # we do not want duplicate handlers to be added in subsequent 
calls of _init_command_logfile_handlers
+            self.command_logger_handler.close()
             
self.command_metadata_logger.removeHandler(self.command_logger_handler)
             self.command_metadata_logger = None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/commands/__init__.py 
new/azure-cli-core-2.5.1/azure/cli/core/commands/__init__.py
--- old/azure-cli-core-2.3.1/azure/cli/core/commands/__init__.py        
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/commands/__init__.py        
2020-04-30 08:18:16.000000000 +0200
@@ -27,7 +27,7 @@
     AzArgumentContext, patch_arg_make_required, patch_arg_make_optional)
 from azure.cli.core.extension import get_extension
 from azure.cli.core.util import get_command_type_kwarg, read_file_content, 
get_arg_list, poller_classes
-from azure.cli.core.local_context import USE
+from azure.cli.core.local_context import GET
 import azure.cli.core.telemetry as telemetry
 
 
@@ -295,7 +295,7 @@
     def _resolve_default_value_from_local_context(self, arg, overrides):
         if self.cli_ctx.local_context.is_on():
             lca = overrides.settings.get('local_context_attribute', None)
-            if not lca or not lca.actions or USE not in lca.actions:
+            if not lca or not lca.actions or GET not in lca.actions:
                 return
             if lca.name:
                 local_context = self.cli_ctx.local_context
@@ -421,15 +421,21 @@
         return _get_operation()
 
 
-def cached_put(cmd_obj, operation, parameters, *args, **kwargs):
-
+def cached_put(cmd_obj, operation, parameters, *args, 
setter_arg_name='parameters', **kwargs):
+    """
+    setter_arg_name: The name of the argument in the setter which corresponds 
to the object being updated.
+    In track2, unknown kwargs will raise, so we should not pass 'parameters" 
for operation when the name of the argument
+    in the setter which corresponds to the object being updated is not 
'parameters'.
+    """
     def _put_operation():
         result = None
         if args:
             extended_args = args + (parameters,)
             result = operation(*extended_args)
         elif kwargs is not None:
-            result = operation(parameters=parameters, **kwargs)
+            kwargs[setter_arg_name] = parameters
+            result = operation(**kwargs)
+            del kwargs[setter_arg_name]
         return result
 
     # early out if the command does not use the cache
@@ -1067,7 +1073,8 @@
             and not isinstance(obj, list) \
             and not isinstance(obj, dict):
         from msrest.paging import Paged
-        return isinstance(obj, Paged)
+        from azure.core.paging import ItemPaged as AzureCorePaged
+        return isinstance(obj, (AzureCorePaged, Paged))
     return False
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/commands/arm.py 
new/azure-cli-core-2.5.1/azure/cli/core/commands/arm.py
--- old/azure-cli-core-2.3.1/azure/cli/core/commands/arm.py     2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/commands/arm.py     2020-04-30 
08:18:16.000000000 +0200
@@ -566,7 +566,7 @@
         if setter_arg_name == 'parameters':
             result = cached_put(cmd, setter, **setterargs)
         else:
-            result = cached_put(cmd, setter, setterargs[setter_arg_name], 
**setterargs)
+            result = cached_put(cmd, setter, setterargs[setter_arg_name], 
setter_arg_name=setter_arg_name, **setterargs)
 
         if supports_no_wait and no_wait_enabled:
             return None
@@ -925,6 +925,8 @@
         except IndexError:
             raise CLIError('index {} doesn\'t exist on {}'
                            .format(list_index, list_attribute_path[-1]))
+        except AttributeError:
+            raise CLIError('{} doesn\'t exist'.format(list_attribute_path[-1]))
 
 
 def throw_and_show_options(instance, part, path):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/commands/client_factory.py 
new/azure-cli-core-2.5.1/azure/cli/core/commands/client_factory.py
--- old/azure-cli-core-2.3.1/azure/cli/core/commands/client_factory.py  
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/commands/client_factory.py  
2020-04-30 08:18:16.000000000 +0200
@@ -7,7 +7,7 @@
 from azure.cli.core.extension import EXTENSIONS_MOD_PREFIX
 from azure.cli.core.profiles._shared import get_client_class, SDKProfile
 from azure.cli.core.profiles import ResourceType, CustomResourceType, 
get_api_version, get_sdk
-from azure.cli.core.util import get_az_user_agent
+from azure.cli.core.util import get_az_user_agent, is_track2
 
 from knack.log import get_logger
 from knack.util import CLIError
@@ -102,6 +102,34 @@
     client.config.generate_client_request_id = 'x-ms-client-request-id' not in 
cli_ctx.data['headers']
 
 
+def configure_common_settings_track2(cli_ctx):
+    client_kwargs = {}
+
+    client_kwargs.update(_debug.change_ssl_cert_verification_track2())
+
+    client_kwargs['logging_enable'] = True
+    client_kwargs['user_agent'] = get_az_user_agent()
+
+    try:
+        command_ext_name = cli_ctx.data['command_extension_name']
+        if command_ext_name:
+            client_kwargs['user_agent'] += 
"CliExtension/{}".format(command_ext_name)
+    except KeyError:
+        pass
+
+    headers = dict(cli_ctx.data['headers'])
+    command_name_suffix = ';completer-request' if 
cli_ctx.data['completer_active'] else ''
+    headers['CommandName'] = "{}{}".format(cli_ctx.data['command'], 
command_name_suffix)
+    if cli_ctx.data.get('safe_params'):
+        headers['ParameterSetName'] = ' '.join(cli_ctx.data['safe_params'])
+    client_kwargs['headers'] = headers
+
+    if 'x-ms-client-request-id' in cli_ctx.data['headers']:
+        client_kwargs['request_id'] = 
cli_ctx.data['headers']['x-ms-client-request-id']
+
+    return client_kwargs
+
+
 def _get_mgmt_service_client(cli_ctx,
                              client_type,
                              subscription_bound=True,
@@ -131,12 +159,16 @@
     if kwargs:
         client_kwargs.update(kwargs)
 
+    if is_track2(client_type):
+        client_kwargs.update(configure_common_settings_track2(cli_ctx))
+
     if subscription_bound:
         client = client_type(cred, subscription_id, **client_kwargs)
     else:
         client = client_type(cred, **client_kwargs)
 
-    configure_common_settings(cli_ctx, client)
+    if not is_track2(client):
+        configure_common_settings(cli_ctx, client)
 
     return client, subscription_id
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/commands/constants.py 
new/azure-cli-core-2.5.1/azure/cli/core/commands/constants.py
--- old/azure-cli-core-2.3.1/azure/cli/core/commands/constants.py       
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/commands/constants.py       
2020-04-30 08:18:16.000000000 +0200
@@ -35,3 +35,7 @@
 SURVEY_PROMPT = 'Please let us know how we are doing: https://aka.ms/clihats'
 SURVEY_PROMPT_COLOR = Fore.YELLOW + Style.BRIGHT + 'Please let us know how we 
are doing: ' + Fore.BLUE + \
     'https://aka.ms/clihats' + Style.RESET_ALL
+UX_SURVEY_PROMPT = 'and let us know if you\'re interested in trying out our 
newest features: https://aka.ms/CLIUXstudy'
+UX_SURVEY_PROMPT_COLOR = Fore.YELLOW + Style.BRIGHT + \
+    'and let us know if you\'re interested in trying out our newest features: 
' \
+    + Fore.BLUE + 'https://aka.ms/CLIUXstudy' + Style.RESET_ALL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/commands/parameters.py 
new/azure-cli-core-2.5.1/azure/cli/core/commands/parameters.py
--- old/azure-cli-core-2.3.1/azure/cli/core/commands/parameters.py      
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/commands/parameters.py      
2020-04-30 08:18:16.000000000 +0200
@@ -12,7 +12,7 @@
 from azure.cli.core.commands.validators import validate_tag, validate_tags, 
generate_deployment_name
 from azure.cli.core.decorators import Completer
 from azure.cli.core.profiles import ResourceType
-from azure.cli.core.local_context import LocalContextAttribute, STORE, USE, ALL
+from azure.cli.core.local_context import LocalContextAttribute, SET, GET, ALL
 
 from knack.arguments import (
     CLIArgumentType, CaseInsensitiveList, ignore_type, ArgumentsContext)
@@ -242,7 +242,7 @@
     configured_default='group',
     local_context_attribute=LocalContextAttribute(
         name='resource_group_name',
-        actions=[STORE, USE],
+        actions=[SET, GET],
         scopes=[ALL]
     ))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/extension/__init__.py 
new/azure-cli-core-2.5.1/azure/cli/core/extension/__init__.py
--- old/azure-cli-core-2.3.1/azure/cli/core/extension/__init__.py       
2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/extension/__init__.py       
2020-04-30 08:18:16.000000000 +0200
@@ -138,24 +138,19 @@
             return None
         metadata = {}
         ext_dir = self.path or get_extension_path(self.name)
-        info_dirs = glob(os.path.join(ext_dir, '*.*-info'))
+        info_dirs = glob(os.path.join(ext_dir, self.name.replace('-', '_') + 
'-' + '*.dist-info'))
+
         azext_metadata = WheelExtension.get_azext_metadata(ext_dir)
         if azext_metadata:
             metadata.update(azext_metadata)
 
         for dist_info_dirname in info_dirs:
-            parsed_dist_info_dir = WHEEL_INFO_RE(dist_info_dirname)
-            if not parsed_dist_info_dir:
-                continue
-
-            parsed_dist_info_dir = parsed_dist_info_dir.groupdict().get('name')
-            if os.path.split(parsed_dist_info_dir)[-1] == 
self.name.replace('-', '_'):
-                whl_metadata_filepath = os.path.join(dist_info_dirname, 
WHL_METADATA_FILENAME)
-                if os.path.isfile(whl_metadata_filepath):
-                    with open(whl_metadata_filepath) as f:
-                        metadata.update(json.loads(f.read()))
-                elif os.path.isfile(os.path.join(dist_info_dirname, 
'PKG-INFO')):
-                    
metadata.update(pkginfo.Develop(dist_info_dirname).__dict__)
+            try:
+                ext_whl_metadata = pkginfo.Wheel(dist_info_dirname)
+                if self.name == ext_whl_metadata.name:
+                    metadata.update(vars(ext_whl_metadata))
+            except ValueError:
+                logger.warning('extension % contains invalid metadata for 
Python Package', self.name)
 
         return metadata
 
@@ -182,13 +177,13 @@
         if os.path.isdir(EXTENSIONS_DIR):
             for ext_name in os.listdir(EXTENSIONS_DIR):
                 ext_path = os.path.join(EXTENSIONS_DIR, ext_name)
-                pattern = os.path.join(ext_path, '*.*-info')
+                pattern = os.path.join(ext_path, '*.dist-info')
                 if os.path.isdir(ext_path) and glob(pattern):
                     exts.append(WheelExtension(ext_name, ext_path))
         if os.path.isdir(EXTENSIONS_SYS_DIR):
             for ext_name in os.listdir(EXTENSIONS_SYS_DIR):
                 ext_path = os.path.join(EXTENSIONS_SYS_DIR, ext_name)
-                pattern = os.path.join(ext_path, '*.*-info')
+                pattern = os.path.join(ext_path, '*.dist-info')
                 if os.path.isdir(ext_path) and glob(pattern):
                     ext = WheelExtension(ext_name, ext_path)
                     if ext not in exts:
@@ -214,27 +209,14 @@
         if azext_metadata:
             metadata.update(azext_metadata)
 
-        def _apply_egginfo_metadata(filename):
-            # extract version info for dev extensions from PKG-INFO
-            if os.path.isfile(filename):
-                with open(filename) as f:
-                    for line in f.readlines():
-                        try:
-                            key, val = line.split(':', 1)
-                            key = key.lower()
-                            if key == 'version':
-                                metadata[key] = '{}'.format(val.strip())
-                            elif key == 'name':
-                                # temporary fix extension name is None
-                                # until wheel upgrade and metadata structure 
in azure-cli-extensions has upgraded too.
-                                # https://github.com/Azure/azure-cli/pull/12583
-                                metadata[key] = val.strip()
-                        except ValueError:
-                            continue
-
         for egg_info_dirname in egg_info_dirs:
-            egg_metadata_filepath = os.path.join(ext_dir, egg_info_dirname, 
EGG_INFO_METADATA_FILE_NAME)
-            _apply_egginfo_metadata(egg_metadata_filepath)
+            egg_metadata_path = os.path.join(ext_dir, egg_info_dirname, )
+            try:
+                ext_whl_metadata = pkginfo.Develop(egg_metadata_path)
+                if self.name == ext_whl_metadata.name:
+                    metadata.update(vars(ext_whl_metadata))
+            except ValueError:
+                logger.warning('extension % contains invalid metadata for 
Python Package', self.name)
 
         return metadata
 
@@ -307,7 +289,6 @@
 
 
 def get_extensions(ext_type=None):
-    logger.debug("Extensions directory: '%s'", EXTENSIONS_DIR)
     extensions = []
     if not ext_type:
         ext_type = EXTENSION_TYPES
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/local_context.py 
new/azure-cli-core-2.5.1/azure/cli/core/local_context.py
--- old/azure-cli-core-2.3.1/azure/cli/core/local_context.py    2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/local_context.py    2020-04-30 
08:18:16.000000000 +0200
@@ -12,8 +12,8 @@
 from knack.config import _ConfigFile
 from knack.util import ensure_dir, CLIError
 
-STORE = 'STORE'   # action for a parameter in local context, STORE means its 
value will be saved to local context
-USE = 'USE'   # action for a parameter in local context, USE means will read 
value from local context for this parameter
+SET = 'SET'   # action for a parameter in local context, SET means its value 
will be saved to local context
+GET = 'GET'   # action for a parameter in local context, GET means will read 
value from local context for this parameter
 ALL = 'ALL'   # effective level of local context, ALL means all commands can 
share this parameter value
 logger = get_logger(__name__)
 
@@ -104,9 +104,9 @@
     def __init__(self, name, actions, scopes=None):
         """ Local Context Attribute arguments
 
-        :param name: Argument name in local context. Make sure it is 
consistent for STORE and USE.
+        :param name: Argument name in local context. Make sure it is 
consistent for SET and GET.
         :type name: str
-        :param actions: Which action should be taken for local context. 
Allowed values: STORE, USE
+        :param actions: Which action should be taken for local context. 
Allowed values: SET, GET
         :type actions: list
         :param scopes: The effective commands or command groups of this 
argument when saved to local context.
         :type scopes: list
@@ -119,6 +119,6 @@
 
         if isinstance(scopes, str):
             scopes = [scopes]
-        if scopes is None and STORE in actions:
+        if scopes is None and SET in actions:
             scopes = [ALL]
         self.scopes = scopes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/parser.py 
new/azure-cli-core-2.5.1/azure/cli/core/parser.py
--- old/azure-cli-core-2.3.1/azure/cli/core/parser.py   2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/parser.py   2020-04-30 
08:18:16.000000000 +0200
@@ -15,6 +15,7 @@
 from azure.cli.core.azlogging import CommandLoggerContext
 from azure.cli.core.extension import get_extension
 from azure.cli.core.commands import ExtensionCommandSource
+from azure.cli.core.commands import AzCliCommandInvoker
 from azure.cli.core.commands.events import EVENT_INVOKER_ON_TAB_COMPLETION
 
 from knack.log import get_logger
@@ -52,8 +53,17 @@
 class AzCliCommandParser(CLICommandParser):
     """ArgumentParser implementation specialized for the Azure CLI utility."""
 
+    @staticmethod
+    def recommendation_provider(version, command, parameters, extension):  # 
pylint: disable=unused-argument
+        logger.debug("recommendation_provider: version: %s, command: %s, 
parameters: %s, extension: %s",
+                     version, command, parameters, extension)
+        return []
+
     def __init__(self, cli_ctx=None, cli_help=None, **kwargs):
         self.command_source = kwargs.pop('_command_source', None)
+        self._raw_arguments = None
+        self._namespace = None
+        self._suggestion_msg = []
         self.subparser_map = {}
         self.specified_arguments = []
         super(AzCliCommandParser, self).__init__(cli_ctx, cli_help=cli_help, 
**kwargs)
@@ -141,6 +151,9 @@
         with CommandLoggerContext(logger):
             logger.error('%(prog)s: error: %(message)s', args)
         self.print_usage(sys.stderr)
+        failure_recovery_recommendations = 
self._get_failure_recovery_recommendations()
+        self._suggestion_msg.extend(failure_recovery_recommendations)
+        self._print_suggestion_msg(sys.stderr)
         self.exit(2)
 
     def format_help(self):
@@ -165,12 +178,96 @@
         argcomplete.autocomplete(self, validator=lambda c, p: 
c.lower().startswith(p.lower()),
                                  default_completer=lambda _: ())
 
+    def _get_failure_recovery_arguments(self, action=None):
+        # Strip the leading "az " and any extraneous whitespace.
+        command = self.prog[3:].strip()
+        parameters = []
+        parameter_set = set()
+        raw_arguments = None
+        extension = None
+
+        # Extract only parameter names to ensure GPDR compliance
+        def extract_safe_params(parameters):
+            return AzCliCommandInvoker._extract_parameter_names(parameters)  # 
pylint: disable=protected-access
+
+        # Check for extension name attribute
+        def has_extension_name(command_source):
+            is_extension_command_source = isinstance(command_source, 
ExtensionCommandSource)
+            has_extension_name = False
+
+            if is_extension_command_source:
+                has_extension_name = hasattr(command_source, 'extension_name')
+
+            return is_extension_command_source and has_extension_name
+
+        # If the arguments have been processed into a namespace...
+        if self._namespace:
+            # Select the parsed command.
+            if hasattr(self._namespace, 'command'):
+                command = self._namespace.command
+        # Parse parameter names from user input.
+        if self._raw_arguments:
+            raw_arguments = self._raw_arguments
+            parameters = extract_safe_params(self._raw_arguments)
+
+        for parameter in parameters:
+            parameter_set.add(parameter)
+
+        # If we can retrieve the extension from the current parser's command 
source...
+        if has_extension_name(self.command_source):
+            extension = self.command_source.extension_name
+        # Otherwise, the command may have not been in a command group. The 
command source will not be
+        # set in this case.
+        elif action and action.dest == '_subcommand':
+            # Get all parsers in the set of possible actions.
+            parsers = list(action.choices.values())
+            parser = parsers[0] if parsers else None
+            # If the first parser comes from an extension...
+            if parser and has_extension_name(parser.command_source):
+                # We're looking for a subcommand under an extension command 
group. Set the
+                # extension to reflect this.
+                extension = parser.command_source.extension_name
+            # Extend the command if the first raw argument is not a parameter.
+            if raw_arguments and raw_arguments[0] not in parameter_set:
+                command = '{cmd} {arg}'.format(cmd=command, 
arg=raw_arguments[0])
+        # Otherwise, only set the extension if every subparser comes from an 
extension. This occurs
+        # when an unrecognized argument is passed to a command from an 
extension.
+        elif isinstance(self.subparser_map, dict):
+            for _, subparser in self.subparser_map.items():
+                if isinstance(subparser.command_source, 
ExtensionCommandSource):
+                    extension = subparser.command_source.extension_name
+                else:
+                    extension = None
+                    break
+
+        return command, parameters, extension
+
+    def _get_failure_recovery_recommendations(self, action=None, **kwargs):
+        # Gets failure recovery recommendations
+        from azure.cli.core import __version__ as core_version
+        failure_recovery_arguments = 
self._get_failure_recovery_arguments(action)
+        recommendations = 
AzCliCommandParser.recommendation_provider(core_version,
+                                                                     
*failure_recovery_arguments,
+                                                                     **kwargs)
+        return recommendations
+
     def _get_values(self, action, arg_strings):
         value = super(AzCliCommandParser, self)._get_values(action, 
arg_strings)
         if action.dest and isinstance(action.dest, str) and not 
action.dest.startswith('_'):
             self.specified_arguments.append(action.dest)
         return value
 
+    def _print_suggestion_msg(self, file=None):
+        if self._suggestion_msg:
+            print('\n'.join(self._suggestion_msg), file=file)
+
+    def parse_known_args(self, args=None, namespace=None):
+        # retrieve the raw argument list in case parsing known arguments fails.
+        self._raw_arguments = args
+        # if parsing known arguments succeeds, get the command namespace and 
the argument list
+        self._namespace, self._raw_arguments = 
super().parse_known_args(args=args, namespace=namespace)
+        return self._namespace, self._raw_arguments
+
     def _check_value(self, action, value):
         # Override to customize the error message when a argument is not among 
the available choices
         # converted value must be one of the choices (if specified)
@@ -198,8 +295,10 @@
                     'verb': 'are' if len(candidates) > 1 else 'is',
                     'value': value
                 }
-                suggestion_msg = "\nThe most similar choice{s} to '{value}' 
{verb}:\n".format(**print_args)
-                suggestion_msg += '\n'.join(['\t' + candidate for candidate in 
candidates])
-                print(suggestion_msg, file=sys.stderr)
+                self._suggestion_msg.append("\nThe most similar choice{s} to 
'{value}' {verb}:".format(**print_args))
+                self._suggestion_msg.append('\n'.join(['\t' + candidate for 
candidate in candidates]))
 
+            failure_recovery_recommendations = 
self._get_failure_recovery_recommendations(action)
+            self._suggestion_msg.extend(failure_recovery_recommendations)
+            self._print_suggestion_msg(sys.stderr)
             self.exit(2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure/cli/core/profiles/_shared.py 
new/azure-cli-core-2.5.1/azure/cli/core/profiles/_shared.py
--- old/azure-cli-core-2.3.1/azure/cli/core/profiles/_shared.py 2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/profiles/_shared.py 2020-04-30 
08:18:16.000000000 +0200
@@ -47,15 +47,18 @@
     MGMT_RESOURCE_POLICY = ('azure.mgmt.resource.policy', 'PolicyClient')
     MGMT_RESOURCE_RESOURCES = ('azure.mgmt.resource.resources', 
'ResourceManagementClient')
     MGMT_RESOURCE_SUBSCRIPTIONS = ('azure.mgmt.resource.subscriptions', 
'SubscriptionClient')
+    MGMT_RESOURCE_DEPLOYMENTSCRIPTS = 
('azure.mgmt.resource.deploymentscripts', 'DeploymentScriptsClient')
     MGMT_MONITOR = ('azure.mgmt.monitor', 'MonitorManagementClient')
     DATA_KEYVAULT = ('azure.keyvault', 'KeyVaultClient')
     MGMT_EVENTHUB = ('azure.mgmt.eventhub', 'EventHubManagementClient')
     MGMT_APPSERVICE = ('azure.mgmt.web', 'WebSiteManagementClient')
     MGMT_IOTHUB = ('azure.mgmt.iothub', 'IotHubClient')
+    MGMT_ARO = ('azure.mgmt.redhatopenshift', 'AzureRedHatOpenShiftClient')
     # the "None" below will stay till a command module fills in the type so 
"get_mgmt_service_client"
     # can be provided with "ResourceType.XXX" to initialize the client object. 
This usually happens
     # when related commands start to support Multi-API
     DATA_STORAGE = ('azure.multiapi.storage', None)
+    DATA_STORAGE_BLOB = ('azure.multiapi.storagev2.blob', None)
     DATA_COSMOS_TABLE = ('azure.multiapi.cosmosdb', None)
     MGMT_CONTAINERSERVICE = ('azure.mgmt.containerservice', None)
     MGMT_ADVISOR = ('azure.mgmt.advisor', None)
@@ -124,12 +127,14 @@
 AZURE_API_PROFILES = {
     'latest': {
         ResourceType.MGMT_STORAGE: '2019-06-01',
-        ResourceType.MGMT_NETWORK: '2019-11-01',
+        ResourceType.MGMT_NETWORK: '2020-03-01',
         ResourceType.MGMT_COMPUTE: SDKProfile('2019-07-01', {
             'resource_skus': '2019-04-01',
             'disks': '2019-11-01',
             'snapshots': '2019-07-01',
-            'galleries': '2019-07-01',
+            'galleries': '2019-12-01',
+            'gallery_images': '2019-12-01',
+            'gallery_image_versions': '2019-12-01',
             'virtual_machine_scale_sets': '2019-12-01'
         }),
         ResourceType.MGMT_RESOURCE_FEATURES: '2015-12-01',
@@ -138,6 +143,7 @@
         ResourceType.MGMT_RESOURCE_POLICY: '2019-09-01',
         ResourceType.MGMT_RESOURCE_RESOURCES: '2019-07-01',
         ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2019-06-01',
+        ResourceType.MGMT_RESOURCE_DEPLOYMENTSCRIPTS: '2019-10-01-preview',
         ResourceType.MGMT_NETWORK_DNS: '2018-05-01',
         ResourceType.MGMT_KEYVAULT: '2019-09-01',
         ResourceType.MGMT_AUTHORIZATION: SDKProfile('2018-09-01-preview', {
@@ -148,6 +154,7 @@
         ResourceType.MGMT_CONTAINERREGISTRY: '2019-12-01-preview',
         ResourceType.DATA_KEYVAULT: '7.0',
         ResourceType.DATA_STORAGE: '2018-11-09',
+        ResourceType.DATA_STORAGE_BLOB: '2019-07-07',
         ResourceType.DATA_COSMOS_TABLE: '2017-04-17',
         ResourceType.MGMT_EVENTHUB: '2017-04-01',
         ResourceType.MGMT_MONITOR: SDKProfile('2019-06-01', {
@@ -174,10 +181,16 @@
             'scheduled_query_rules': '2018-04-16',
             'service_diagnostic_settings': '2016-09-01',
             'tenant_activity_logs': '2015-04-01',
-            'vm_insights': '2018-11-27-preview'
+            'vm_insights': '2018-11-27-preview',
+            'private_link_resources': '2019-10-17-preview',
+            'private_link_scoped_resources': '2019-10-17-preview',
+            'private_link_scope_operation_status': '2019-10-17-preview',
+            'private_link_scopes': '2019-10-17-preview',
+            'private_endpoint_connections': '2019-10-17-preview'
         }),
         ResourceType.MGMT_APPSERVICE: '2019-08-01',
-        ResourceType.MGMT_IOTHUB: '2019-07-01-preview'
+        ResourceType.MGMT_IOTHUB: '2019-07-01-preview',
+        ResourceType.MGMT_ARO: '2020-04-30'
     },
     '2019-03-01-hybrid': {
         ResourceType.MGMT_STORAGE: '2017-10-01',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/telemetry.py 
new/azure-cli-core-2.5.1/azure/cli/core/telemetry.py
--- old/azure-cli-core-2.3.1/azure/cli/core/telemetry.py        2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/telemetry.py        2020-04-30 
08:18:16.000000000 +0200
@@ -173,7 +173,8 @@
         set_custom_properties(result, 'Feedback', self.feedback)
         set_custom_properties(result, 'ExtensionManagementDetail', 
self.extension_management_detail)
         set_custom_properties(result, 'Mode', self.mode)
-        set_custom_properties(result, 'Installer', os.getenv('AZ_INSTALLER'))
+        from azure.cli.core._environment import _ENV_AZ_INSTALLER
+        set_custom_properties(result, 'Installer', 
os.getenv(_ENV_AZ_INSTALLER))
 
         return result
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/azure/cli/core/util.py 
new/azure-cli-core-2.5.1/azure/cli/core/util.py
--- old/azure-cli-core-2.3.1/azure/cli/core/util.py     2020-04-01 
09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure/cli/core/util.py     2020-04-30 
08:18:16.000000000 +0200
@@ -16,9 +16,12 @@
 import logging
 
 from six.moves.urllib.request import urlopen  # pylint: disable=import-error
+
+from azure.common import AzureException
+from azure.core.exceptions import AzureError
 from knack.log import get_logger
 from knack.util import CLIError, to_snake_case
-from azure.common import AzureException
+from inspect import getfullargspec as get_arg_spec
 
 logger = get_logger(__name__)
 
@@ -51,8 +54,15 @@
             logger.error("To learn more about --query, please visit: "
                          
"https://docs.microsoft.com/cli/azure/query-azure-cli?view=azure-cli-latest";)
             return 1
-        if isinstance(ex, (CLIError, CloudError, AzureException)):
+        if isinstance(ex, (CLIError, CloudError, AzureException, AzureError)):
             logger.error(ex.args[0])
+            try:
+                for detail in ex.args[0].error.details:
+                    logger.error(detail)
+            except (AttributeError, TypeError):
+                pass
+            except:  # pylint: disable=bare-except
+                pass
             return ex.args[1] if len(ex.args) >= 2 else 1
         if isinstance(ex, ValidationError):
             logger.error('validation error: %s', ex)
@@ -200,9 +210,6 @@
     _print()
     _print('Legal docs and information: aka.ms/AzureCliLegal')
     _print()
-    if sys.version.startswith('2.7'):
-        _print("* DEPRECATION: Python 2.7 will reach the end of its life on 
January 1st, 2020. \nA future version of Azure CLI will drop support for Python 
2.7.")
-    _print()
     version_string = output.getvalue()
 
     # if unable to query PyPI, use sentinel value to flag that
@@ -358,6 +365,14 @@
         return sig.args
 
 
+def is_track2(client_class):
+    """ IS this client a autorestv3/track2 one?.
+    Could be refined later if necessary.
+    """
+    args = get_arg_spec(client_class.__init__).args
+    return "credential" in args
+
+
 DISABLE_VERIFY_VARIABLE_NAME = "AZURE_CLI_DISABLE_CONNECTION_VERIFICATION"
 
 
@@ -369,7 +384,8 @@
 def poller_classes():
     from msrestazure.azure_operation import AzureOperationPoller
     from msrest.polling.poller import LROPoller
-    return (AzureOperationPoller, LROPoller)
+    from azure.core.polling import LROPoller as AzureCoreLROPoller
+    return (AzureOperationPoller, LROPoller, AzureCoreLROPoller)
 
 
 def augment_no_wait_handler_args(no_wait_enabled, handler, handler_args):
@@ -387,7 +403,7 @@
 
 def sdk_no_wait(no_wait, func, *args, **kwargs):
     if no_wait:
-        kwargs.update({'raw': True, 'polling': False})
+        kwargs.update({'polling': False})
     return func(*args, **kwargs)
 
 
@@ -537,7 +553,7 @@
     return success
 
 
-def send_raw_request(cli_ctx, method, uri, headers=None, uri_parameters=None,  
# pylint: disable=too-many-locals,too-many-branches,too-many-statements
+def send_raw_request(cli_ctx, method, url, headers=None, uri_parameters=None,  
# pylint: disable=too-many-locals,too-many-branches,too-many-statements
                      body=None, skip_authorization_header=False, 
resource=None, output_file=None,
                      
generated_client_request_id_name='x-ms-client-request-id'):
     import uuid
@@ -600,26 +616,26 @@
             result[key] = value
     uri_parameters = result or None
 
-    # If uri is an ARM resource ID, like 
/subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01,
+    # If url is an ARM resource ID, like 
/subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01,
     # default to Azure Resource Manager.
     # https://management.azure.com/ + 
subscriptions/xxx/resourcegroups/xxx?api-version=2019-07-01
-    if '://' not in uri:
-        uri = cli_ctx.cloud.endpoints.resource_manager + uri.lstrip('/')
+    if '://' not in url:
+        url = cli_ctx.cloud.endpoints.resource_manager + url.lstrip('/')
 
     # Replace common tokens with real values. It is for smooth experience if 
users copy and paste the url from
     # Azure Rest API doc
     from azure.cli.core._profile import Profile
     profile = Profile()
-    if '{subscriptionId}' in uri:
-        uri = uri.replace('{subscriptionId}', profile.get_subscription_id())
+    if '{subscriptionId}' in url:
+        url = url.replace('{subscriptionId}', profile.get_subscription_id())
 
-    if not skip_authorization_header and uri.lower().startswith('https://'):
+    if not skip_authorization_header and url.lower().startswith('https://'):
         if not resource:
             endpoints = cli_ctx.cloud.endpoints
-            # If uri starts with ARM endpoint, like 
https://management.azure.com/,
+            # If url starts with ARM endpoint, like 
https://management.azure.com/,
             # use active_directory_resource_id for resource.
             # This follows the same behavior as 
azure.cli.core.commands.client_factory._get_mgmt_service_client
-            if uri.lower().startswith(endpoints.resource_manager.rstrip('/')):
+            if url.lower().startswith(endpoints.resource_manager.rstrip('/')):
                 resource = endpoints.active_directory_resource_id
             else:
                 from azure.cli.core.cloud import CloudEndpointNotSetException
@@ -628,7 +644,7 @@
                         value = getattr(endpoints, p)
                     except CloudEndpointNotSetException:
                         continue
-                    if isinstance(value, six.string_types) and 
uri.lower().startswith(value.lower()):
+                    if isinstance(value, six.string_types) and 
url.lower().startswith(value.lower()):
                         resource = value
                         break
         if resource:
@@ -643,7 +659,7 @@
     try:
         # 
https://requests.readthedocs.io/en/latest/user/advanced/#prepared-requests
         s = Session()
-        req = Request(method=method, url=uri, headers=headers, 
params=uri_parameters, data=body)
+        req = Request(method=method, url=url, headers=headers, 
params=uri_parameters, data=body)
         prepped = s.prepare_request(req)
 
         # Merge environment settings into session
@@ -805,8 +821,8 @@
 
     agents = ["AZURECLI/{}".format(core_version)]
 
-    _ENV_AZ_INSTALLER = 'AZ_INSTALLER'
     import os
+    from azure.cli.core._environment import _ENV_AZ_INSTALLER
     if _ENV_AZ_INSTALLER in os.environ:
         agents.append('({})'.format(os.environ[_ENV_AZ_INSTALLER]))
 
@@ -828,3 +844,22 @@
     except NoTTYException:
         raise CLIError(
             'Unable to prompt for confirmation as no tty available. Use 
--yes.')
+
+
+def get_linux_distro():
+    if platform.system() != 'Linux':
+        return None, None
+
+    try:
+        with open('/etc/os-release') as lines:
+            tokens = [line.strip() for line in lines]
+    except Exception:  # pylint: disable=broad-except
+        return None, None
+
+    release_info = {}
+    for token in tokens:
+        if '=' in token:
+            k, v = token.split('=', 1)
+            release_info[k.lower()] = v.strip('"')
+
+    return release_info.get('name', None), release_info.get('version_id', None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure_cli_core.egg-info/PKG-INFO 
new/azure-cli-core-2.5.1/azure_cli_core.egg-info/PKG-INFO
--- old/azure-cli-core-2.3.1/azure_cli_core.egg-info/PKG-INFO   2020-04-01 
09:16:27.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure_cli_core.egg-info/PKG-INFO   2020-04-30 
08:18:30.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: azure-cli-core
-Version: 2.3.1
+Version: 2.5.1
 Summary: Microsoft Azure Command-Line Tools Core Module
 Home-page: https://github.com/Azure/azure-cli
 Author: Microsoft Corporation
@@ -15,6 +15,27 @@
         Release History
         ===============
         
+        2.5.1
+        ++++++
+        * Minor fixes
+        
+        2.5.0
+        ++++++
+        * Fix logging file fd leaking (#13102)
+        * Fix core tests failed under certain profiles (#13136)
+        * Use pkginfo to query metadata for Python Package (#12782)
+        
+        2.4.0
+        ++++++
+        * Upgrade msrestazure to 0.6.3 (#12839)
+        * Output more error details of exceptions if possible (#12945)
+        * Support track1 and track2 mgmt SDK side by side (#12952)
+        * Fix generic remove property NoneType exception (#12950)
+        * `az --version`: Show command instruction and detailed instruction 
link when updates available (#12981)
+        * Fix bug in core test test_parser that will affect exception stack 
while existing if argument parse raise Exception
+        * Make CLI respect file logging configuration option: enable_log_file 
and AZURE_LOGGING_ENABLE_LOG_FILE env variable
+        * Fix the name of extension of dev type is None if it has 
incompatibility problem with core
+        
         2.3.1
         ++++++
         * No changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure_cli_core.egg-info/SOURCES.txt 
new/azure-cli-core-2.5.1/azure_cli_core.egg-info/SOURCES.txt
--- old/azure-cli-core-2.3.1/azure_cli_core.egg-info/SOURCES.txt        
2020-04-01 09:16:27.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure_cli_core.egg-info/SOURCES.txt        
2020-04-30 08:18:30.000000000 +0200
@@ -13,6 +13,7 @@
 azure/cli/core/_environment.py
 azure/cli/core/_help.py
 azure/cli/core/_help_loaders.py
+azure/cli/core/_msal.py
 azure/cli/core/_output.py
 azure/cli/core/_profile.py
 azure/cli/core/_session.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/azure-cli-core-2.3.1/azure_cli_core.egg-info/requires.txt 
new/azure-cli-core-2.5.1/azure_cli_core.egg-info/requires.txt
--- old/azure-cli-core-2.3.1/azure_cli_core.egg-info/requires.txt       
2020-04-01 09:16:27.000000000 +0200
+++ new/azure-cli-core-2.5.1/azure_cli_core.egg-info/requires.txt       
2020-04-30 08:18:30.000000000 +0200
@@ -4,18 +4,19 @@
 colorama>=0.3.9
 humanfriendly<9.0,>=4.7
 jmespath
-knack==0.7.0rc1
+knack==0.7.0rc4
+msal~=1.0.0
+msal-extensions~=0.1.3
 msrest>=0.4.4
-msrestazure>=0.6.2
+msrestazure>=0.6.3
 paramiko<3.0.0,>=2.0.8
-pkginfo
 PyJWT
 pyopenssl>=17.1.0
-pyyaml~=5.2
 requests~=2.20
 six~=1.12
-wheel==0.30.0
-azure-mgmt-resource==8.0.1
+pkginfo>=1.5.0.1
+azure-mgmt-resource==9.0.0
+azure-mgmt-core==1.0.0
 
 [:python_version<"3.0"]
 futures
@@ -25,14 +26,8 @@
 ndg-httpsclient
 pyasn1
 
-[:python_version<'3.0']
-antlr4-python2-runtime
-
 [:python_version<'3.4']
 enum34
 
-[:python_version>='3.0']
-antlr4-python3-runtime
-
 [test]
 mock
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/azure-cli-core-2.3.1/setup.py 
new/azure-cli-core-2.5.1/setup.py
--- old/azure-cli-core-2.3.1/setup.py   2020-04-01 09:16:17.000000000 +0200
+++ new/azure-cli-core-2.5.1/setup.py   2020-04-30 08:18:16.000000000 +0200
@@ -17,7 +17,7 @@
     logger.warn("Wheel is not available, disabling bdist_wheel hook")
     cmdclass = {}
 
-VERSION = "2.3.1"
+VERSION = "2.5.1"
 # If we have source, validate that our version numbers match
 # This should prevent uploading releases with mismatched versions.
 try:
@@ -56,18 +56,19 @@
     'colorama>=0.3.9',
     'humanfriendly>=4.7,<9.0',
     'jmespath',
-    'knack==0.7.0rc1',
+    'knack==0.7.0rc4',
+    'msal~=1.0.0',
+    'msal-extensions~=0.1.3',
     'msrest>=0.4.4',
-    'msrestazure>=0.6.2',
+    'msrestazure>=0.6.3',
     'paramiko>=2.0.8,<3.0.0',
-    'pkginfo',
     'PyJWT',
     'pyopenssl>=17.1.0',  # https://github.com/pyca/pyopenssl/pull/612
-    'pyyaml~=5.2',
     'requests~=2.20',
     'six~=1.12',
-    'wheel==0.30.0',
-    'azure-mgmt-resource==8.0.1',
+    'pkginfo>=1.5.0.1',
+    'azure-mgmt-resource==9.0.0',
+    'azure-mgmt-core==1.0.0'
 ]
 
 TESTS_REQUIRE = [
@@ -103,8 +104,6 @@
         ":python_version<'3.4'": ['enum34'],
         ":python_version<'2.7.9'": ['pyopenssl', 'ndg-httpsclient', 'pyasn1'],
         ':python_version<"3.0"': ['futures'],
-        ":python_version<'3.0'": ['antlr4-python2-runtime'],
-        ":python_version>='3.0'": ['antlr4-python3-runtime'],
         "test": TESTS_REQUIRE,
     },
     tests_require=TESTS_REQUIRE,


Reply via email to