Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add command-change version diff #376

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions azdev/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def operation_group(name):
with CommandGroup(self, 'command-change', operation_group('command_change')) as g:
g.command('meta-export', 'export_command_meta')
g.command('meta-diff', 'cmp_command_meta')
g.command('version-diff', 'cmp_command_meta_of_versions')

with CommandGroup(self, 'cli', operation_group('pypi')) as g:
g.command('check-versions', 'verify_versions')
Expand Down
49 changes: 47 additions & 2 deletions azdev/operations/command_change/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
from deepdiff import DeepDiff
from knack.log import get_logger

from azdev.utilities import display, require_azure_cli, heading, get_path_table, filter_by_git_diff
from azdev.utilities import display, require_azure_cli, heading, get_path_table, filter_by_git_diff, cmd
from .custom import MetaChangeDetects, DiffExportFormat
from .util import export_meta_changes_to_json, gen_commands_meta, get_commands_meta
from .util import export_meta_changes_to_json, gen_commands_meta, get_commands_meta, \
extrct_module_name_from_meta_file, export_meta_changes_to_csv
from ..statistics import _create_invoker_and_load_cmds, _get_command_source, \
_command_codegen_info # pylint: disable=protected-access
from ..statistics.util import filter_modules
Expand Down Expand Up @@ -140,3 +141,47 @@ def cmp_command_meta(base_meta_file, diff_meta_file, only_break=False, output_ty
detected_changes.check_deep_diffs()
result = detected_changes.export_meta_changes(only_break, output_type)
return export_meta_changes_to_json(result, output_file)


def cmp_command_meta_of_versions(base_version, diff_version, only_break=False, version_diff_file=None):
version_diffs = []
base_version_meta_path = "azure-cli-" + base_version
base_meta_download_cmd = """az storage blob download-batch --account-name versionmeta -s $web --pattern """ \
+ base_version_meta_path + """/* -d . """
display(f"Downloading {base_version} meta data using '{base_meta_download_cmd}'")
cmd(base_meta_download_cmd, show_stderr=True)
if not os.path.exists(os.getcwd() + "/" + base_version_meta_path):
display(f"No meta downloaded from blob for {base_version}, please check blob data")
return export_meta_changes_to_csv(version_diffs, version_diff_file)
diff_version_meta_path = "azure-cli-" + diff_version
diff_meta_download_cmd = """az storage blob download-batch --account-name versionmeta -s $web --pattern """ \
+ diff_version_meta_path + """/* -d . """
display(f"Downloading {diff_version} meta data using '{diff_meta_download_cmd}'")
cmd(diff_meta_download_cmd, show_stderr=True)
if not os.path.exists(os.getcwd() + "/" + diff_version_meta_path):
display(f"No meta downloaded from blob for {diff_version}, please check blob data")
return export_meta_changes_to_csv(version_diffs, version_diff_file)
for base_meta_file in os.listdir(os.getcwd() + "/" + base_version_meta_path):
module_name = extrct_module_name_from_meta_file(base_meta_file)
if not module_name:
continue
diff_meta_file = os.path.join(os.getcwd(), diff_version_meta_path, base_meta_file)
if not os.path.exists(diff_meta_file):
display(f"Module {module_name} removed for {diff_version}")
continue
with open(os.path.join(base_version_meta_path, base_meta_file), "r") as g:
command_tree_before = json.load(g)
with open(diff_meta_file, "r") as g:
command_tree_after = json.load(g)
diff = DeepDiff(command_tree_before, command_tree_after)
if not diff:
display(f"No meta diffs from version: {diff_version}/{base_meta_file} for module: {module_name}")
continue
detected_changes = MetaChangeDetects(diff, command_tree_before, command_tree_after)
detected_changes.check_deep_diffs()
diff_objs = detected_changes.export_meta_changes(only_break, "dict")
mod_obj = {"module": module_name}
for obj in diff_objs:
obj.update(mod_obj)
version_diffs.append(obj)
return export_meta_changes_to_csv(version_diffs, version_diff_file)
38 changes: 38 additions & 0 deletions azdev/operations/command_change/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import json
import os
import re
import csv
from enum import Enum
import jsbeautifier
from knack.log import get_logger
Expand All @@ -16,6 +17,10 @@
SUBGROUP_NAME_PATTERN = re.compile(r"\[\'sub_groups\'\]\[\'([a-zA-Z0-9\-\s]+)\'\]")
CMD_NAME_PATTERN = re.compile(r"\[\'commands\'\]\[\'([a-zA-Z0-9\-\s]+)\'\]")
CMD_PARAMETER_PROPERTY_PATTERN = re.compile(r"\[(.*?)\]")
MODULE_NAME_PATTERN = re.compile(r"az_([a-zA-Z0-9\-\_]+)_meta.json")

EXPORTED_CSV_META_HEADER = ["module", "cmd_name", "rule_id", "rule_name", "is_break",
"rule_message", "suggest_message"]


class ChangeType(int, Enum):
Expand Down Expand Up @@ -215,6 +220,13 @@ def extract_para_info(key):
return property_res


def extrct_module_name_from_meta_file(file_name):
name_res = re.findall(MODULE_NAME_PATTERN, file_name)
if not name_res or len(name_res) == 0:
return None
return name_res[0]


def export_meta_changes_to_json(output, output_file):
if not output_file:
return output
Expand All @@ -225,3 +237,29 @@ def export_meta_changes_to_json(output, output_file):
if output:
f_out.write(json.dumps(output, indent=4))
return None


def format_module_diff_csv(module_diffs):
csv_res = [EXPORTED_CSV_META_HEADER]
for diff_obj in module_diffs:
_row = []
for attr in EXPORTED_CSV_META_HEADER:
if attr == "cmd_name":
_row.append(diff_obj.get(attr, None) or diff_obj.get("subgroup_name", "-"))
else:
_row.append(diff_obj.get(attr, None))
csv_res.append(_row)
return csv_res


def export_meta_changes_to_csv(module_diffs, version_diff_file):
csv_res = format_module_diff_csv(module_diffs)
if not version_diff_file:
return csv_res
diff_file_folder = os.path.dirname(version_diff_file)
if diff_file_folder and not os.path.exists(diff_file_folder):
os.makedirs(diff_file_folder)
with open(version_diff_file, "w", newline='') as f:
writer = csv.writer(f)
writer.writerows(csv_res)
return None
5 changes: 5 additions & 0 deletions azdev/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ def load_arguments(self, _):
help='format to print diff and suggest message')
c.argument('output_file', help='command meta diff json file path to store')

with ArgumentsContext(self, 'command-change version-diff') as c:
c.argument('base_version', required=True, help='azure cli version as base')
c.argument('diff_version', required=True, help='azure cli version to diff')
c.argument('version_diff_file', help='command meta version diff file path to store')

with ArgumentsContext(self, 'perf') as c:
c.argument('runs', type=int, help='Number of runs to average performance over.')

Expand Down