Regression fixes for command execution

Change-Id: I8591a206268b7afcb8f561f2eab4fc21b2172fc1
Related-PROD: PROD-28199
diff --git a/cfg_checker/cli/command.py b/cfg_checker/cli/command.py
index 8e715f2..9ac05f3 100644
--- a/cfg_checker/cli/command.py
+++ b/cfg_checker/cli/command.py
@@ -32,7 +32,10 @@
 
 def execute_command(args, command):
     # Validate the commands
-    # check command
+    # check commands
+    if not hasattr(args, 'type') or not args.type:
+        logger_cli.info("\n# Please, type a command listed above")
+        return 0
     _type = args.type.replace("-", "_") if "-" in args.type else args.type
     if command not in commands:
         logger_cli.info("\n# Please, type a command listed above")
diff --git a/cfg_checker/cli/reclass.py b/cfg_checker/cli/reclass.py
index 24eb8e2..f479a72 100644
--- a/cfg_checker/cli/reclass.py
+++ b/cfg_checker/cli/reclass.py
@@ -4,7 +4,7 @@
 def entrypoint():
     cli_command(
         '# Mirantis Cloud Reclass comparer"',
-        'packages'
+        'reclass'
     )
 
 
diff --git a/cfg_checker/modules/network/__init__.py b/cfg_checker/modules/network/__init__.py
index c81b63a..b1664a4 100644
--- a/cfg_checker/modules/network/__init__.py
+++ b/cfg_checker/modules/network/__init__.py
@@ -114,16 +114,14 @@
     # Should generate network map to console or HTML
     logger_cli.info("# Network report")
 
-    _type, _filename = args_utils.get_network_map_type_and_filename(args)
     networkMap = _prepare_map()
-
     networkMap.print_map()
 
     return
 
 
 def do_list(args):
-    # Network Map
+    # Network List
     # Should generate network map to console or HTML
     _map = mapper.NetworkMapper()
     reclass = _map.map_network(_map.RECLASS)
diff --git a/cfg_checker/modules/packages/checker.py b/cfg_checker/modules/packages/checker.py
index bf192f9..83ecc94 100644
--- a/cfg_checker/modules/packages/checker.py
+++ b/cfg_checker/modules/packages/checker.py
@@ -188,9 +188,6 @@
         _total_processed = 0
         # Collect packages from all of the nodes in flat dict
         _all_packages = {}
-        _all_tags = set([])
-        # get env tag's year and major version
-        _tag_major = _mcp[:_mcp.find('.', _mcp.find('.')+1)]
         for node_name, node_value in salt_master.nodes.iteritems():
             _uniq_len = len(_all_packages.keys())
             _progress_index += 1
@@ -205,66 +202,54 @@
             )
             for _name, _value in node_value['packages'].iteritems():
                 _total_processed += 1
-                # Parse versions
+                # Parse versions from nodes
                 _ver_ins = DebianVersion(_value['installed'])
                 _ver_can = DebianVersion(_value['candidate'])
 
-                # All packages list with version and node list
+                # Process package description and release version
+                # at a first sight
                 if _name not in _all_packages:
-                    # get repo versions list,
+                    # get node attributes
                     _linux = salt_master.nodes[node_name]['linux_codename']
                     _arch = salt_master.nodes[node_name]['linux_arch']
-                    if _name == u'qemu-block-extra':
-                        a = 1
-                    # omit tag as target versions might be of different tag
+                    # get versions for this tag and repo headers
+                    # excluding 'nightly' repos
                     _r = self.rm.get_filtered_versions(
                         _name,
                         tag=_mcp,
                         include=[_os, _linux, _arch],
                         exclude=["nightly"]
                     )
-                    # save versions for matching major tags
+                    # repack versions in flat format
                     _vs = {}
                     _sections = {}
                     _apps = {}
-                    # get all versions for this year
                     for s, apps in _r.iteritems():
                         for a, versions in apps.iteritems():
                             for v, repos in versions.iteritems():
                                 for repo in repos:
-                                    t = repo['tag']
-                                    _major = t[:t.find('.', t.find('.')+1)]
-                                    if _tag_major == _major:
-                                        if v not in _vs:
-                                            _vs[v] = []
-                                        _vs[v].append(repo)
-                                        if v not in _sections:
-                                            _sections[v] = []
-                                        _sections[v].append(s)
-                                        if v not in _apps:
-                                            _apps[v] = []
-                                        _apps[v].append(a)
-
-                    # check if we have candidate version among found
+                                    if v not in _vs:
+                                        _vs[v] = []
+                                    _vs[v].append(repo)
+                                    if v not in _sections:
+                                        _sections[v] = []
+                                    _sections[v].append(s)
+                                    if v not in _apps:
+                                        _apps[v] = []
+                                    _apps[v].append(a)
+                    # search for the newest version among filtered
                     _r_desc = []
                     _vs_keys = _vs.keys()
                     if _vs_keys:
                         _newest = _newest = DebianVersion(_vs_keys.pop())
                     else:
                         _newest = DebianVersion('')
-                    # if _ver_ins.version in _vs_keys:
-                    #     # exact match, save it
-                    #     _release = _ver_ins
-                    # else:
-                    # detect newest version among saved
-
                     for v in _vs_keys:
                         _this = DebianVersion(v)
                         if _this > _newest:
                             _newest = _this
-                    # newest version for the YEAR.MAJOR will be the release
                     _release = _newest
-                    # save repos list for this version
+                    # Get best description for the package
                     if _release.version != 'n/a':
                         _r_desc = _vs[_release.version]
                     # preload special description
@@ -272,6 +257,7 @@
                         _pkg_desc = _desc[_name]
                     else:
                         _pkg_desc = _desc.dummy_desc
+                    # Save repos list and desc for this version
                     # Check if we can provide better from the package
                     if _release.version != 'n/a':
                         if not _pkg_desc['section']:
@@ -281,49 +267,7 @@
                             _pkg_desc['app'] = \
                                 "/".join(_apps[_release.version])
 
-                    # get specific set for this OS release if present
-                    # if not, try search in all repos for this tag
-                    # _r_desc = _r[_newest.version]
-                    # if _r:
-                    #     _vs = _r.keys()
-                    #     if len(_vs) > 1:
-                    #         # search best match
-                    #         _release = None
-                    #         for _v in _vs:
-                    #             _deb = DebianVersion(_v)
-                    #             if _ver_can == _deb:
-                    #                 _release = _deb
-                    #                 _r_desc = _r[_v]
-                    #                 break
-                    #         if not _release:
-                    #             _progress.clearline()
-                    #             logger_cli.error(
-                    #                 "# ERROR: No release version found "
-                    #                 "for '{}'".format(_name)
-                    #             )
-                    #             _release = DebianVersion('')
-                    #     else:
-                    #         _release = DebianVersion(_vs[0])
-                    #         _r_desc = _r[_vs[0]]
-                    # else:
-                    #     # not found... 99% that it will not happen
-                    #     _release = DebianVersion('')
-
-                    # Old versions match routine
-                    # ########
-                    # if _os in _vers:
-                    #     _v = _vers[_os]
-                    # elif 'any' in _vers:
-                    #     _v = _vers['any']
-                    # else:
-                    #     _v = {}
-
-                    # Finally, get specific version
-                    # _release = DebianVersion(_v[_mcp] if _mcp in _v else '')
-                    for repo in _r_desc:
-                        _all_tags.add(repo['tag'])
-
-                    # Populate package info
+                    # Populate package info, once for package
                     _m = _r_desc[0]["maintainer"] if _r_desc else 'n/a'
                     _all_packages[_name] = {
                         "desc": _pkg_desc,
@@ -331,18 +275,18 @@
                         "maintainer": _m,
                         "is_mirantis": self.rm.is_mirantis(
                             _name,
-                            tag=_tag_major
+                            tag=_mcp
                         ),
                         "results": {},
                         "r": _release,
                     }
-
+                # Cross-compare versions
                 _cmp = VersionCmpResult(
                     _ver_ins,
                     _ver_can,
                     _all_packages[_name]['r']
                 )
-
+                # Update results structure
                 # shortcut to results
                 _res = _all_packages[_name]['results']
                 # update status
diff --git a/cfg_checker/modules/packages/repos.py b/cfg_checker/modules/packages/repos.py
index e7c4c6a..334cbb5 100644
--- a/cfg_checker/modules/packages/repos.py
+++ b/cfg_checker/modules/packages/repos.py
@@ -821,8 +821,6 @@
             # <10symbols> \t <md5> \t sorted headers with no tag
             # ...
             # section
-            _o = ""
-
             _ss = _p.keys()
             _ss.sort()
             for _s in _ss:
@@ -830,9 +828,8 @@
                 _apps.sort()
                 # app
                 for _a in _apps:
-                    logger_cli.info(
-                        "\n# Package: {}/{}/{}".format(_s, _a, name)
-                    )
+                    _o = ""
+                    _mm = []
                     # get and sort tags
                     _vs = _p[_s][_a].keys()
                     _vs.sort()
@@ -847,18 +844,26 @@
                             _rr = _p[_s][_a][_v][_md5].keys()
                             _rr.sort()
                             for _r in _rr:
-                                _o += " "*24 + _r.replace('_', ' ')
-                                _o += " ({})\n".format(
-                                    _p[_s][_a][_v][_md5][_r]["maintainer"]
-                                )
+                                _o += " "*24 + _r.replace('_', ' ') + '\n'
+                                _m = _p[_s][_a][_v][_md5][_r]["maintainer"]
+                                if _m not in _mm:
+                                    _mm.append(_m)
 
-            logger_cli.info(_o)
+                    logger_cli.info(
+                        "\n# Package: {}/{}/{}\nMaintainers: {}".format(
+                            _s,
+                            _a,
+                            name,
+                            ", ".join(_mm)
+                        )
+                    )
+
+                    logger_cli.info(_o)
 
     @staticmethod
     def get_apps(versions, name):
         _all = True if name == '*' else False
-        _s_max = 0
-        _a_max = 0
+        _s_max = _a_max = _p_max = _v_max = 0
         _rows = []
         for _p in versions.keys():
             _vs = versions[_p]
@@ -867,13 +872,30 @@
                     if _all or name == _info['app']:
                         _s_max = max(len(_info['section']), _s_max)
                         _a_max = max(len(_info['app']), _a_max)
+                        _p_max = max(len(_p), _p_max)
+                        _v_max = max(len(_v), _v_max)
                         _rows.append([
                             _info['section'],
                             _info['app'],
-                            _p
+                            _p,
+                            _v,
+                            _md5,
+                            len(_info['repo'])
                         ])
-        _fmt = "{:"+str(_s_max)+"} {:"+str(_a_max)+"} {}"
-        _rows = [_fmt.format(s, a, p) for s, a, p in _rows]
+        # format columns
+        # section
+        _fmt = "{:"+str(_s_max)+"} "
+        # app
+        _fmt += "{:"+str(_a_max)+"} "
+        # package name
+        _fmt += "{:"+str(_p_max)+"} "
+        # version
+        _fmt += "{:"+str(_v_max)+"} "
+        # md5 and number of repos is fixed
+        _fmt += "{} in {} repos"
+
+        # fill rows
+        _rows = [_fmt.format(s, a, p, v, m, l) for s, a, p, v, m, l in _rows]
         _rows.sort()
         return _rows
 
@@ -881,12 +903,12 @@
         c = 0
         rows = self.get_apps(self._versions_mirantis, name)
         if rows:
-            logger_cli.info("# Mirantis packages for '{}'".format(name))
+            logger_cli.info("\n# Mirantis packages for '{}'".format(name))
             logger_cli.info("\n".join(rows))
             c += 1
         rows = self.get_apps(self._versions_other, name)
         if rows:
-            logger_cli.info("# Other packages for '{}'".format(name))
+            logger_cli.info("\n# Other packages for '{}'".format(name))
             logger_cli.info("\n".join(rows))
             c += 1
         if c == 0:
diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py
index 5fd778a..eb463cc 100644
--- a/tests/test_entrypoints.py
+++ b/tests/test_entrypoints.py
@@ -19,11 +19,13 @@
         with self.redirect_output():
             with self.assertRaises(SystemExit) as ep:
                 _m.cfg_check.config_check_entrypoint()
-
+        # empty run should return code 1
         self.assertEqual(
             ep.exception.code,
-            0,
-            "mcp-checker has non-zero exit-code"
+            1,
+            "mcp-checker has unexpected exit code: {}".format(
+                ep.exception.code
+            )
         )
 
     def test_entry_packages(self):
@@ -43,11 +45,11 @@
         with self.redirect_output():
             with self.assertRaises(SystemExit) as ep:
                 _m.cli.packages.entrypoint()
-
+        # empty run should return code 1
         self.assertEqual(
             ep.exception.code,
-            0,
-            "packages has non-zero exit code"
+            1,
+            "packages has unexpected exit code: {}".format(ep.exception.code)
         )
 
     def test_entry_network(self):
@@ -67,11 +69,11 @@
         with self.redirect_output():
             with self.assertRaises(SystemExit) as ep:
                 _m.cli.network.entrypoint()
-
+        # empty run should return code 1
         self.assertEqual(
             ep.exception.code,
-            0,
-            "network has non-zero exit-code"
+            1,
+            "network has unexpected exit code: {}".format(ep.exception.code)
         )
 
     def test_entry_reclass(self):
@@ -91,9 +93,9 @@
         with self.redirect_output():
             with self.assertRaises(SystemExit) as ep:
                 _m.cli.reclass.entrypoint()
-
+        # empty run should return code 1
         self.assertEqual(
             ep.exception.code,
-            0,
-            "reclass has non-zero exit-code"
+            1,
+            "reclass has unexpected exit code: {}".format(ep.exception.code)
         )