From 4dc27209fdd2d15599fc59c53a3502675d606c27 Mon Sep 17 00:00:00 2001 From: Eugene Breen <49158625+eugenebreenire@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:49:39 +0000 Subject: [PATCH] Compare plugin initial integration --- compare-plugin/README.md | 54 + compare-plugin/__init__.py | 0 compare-plugin/config.json | 10 + compare-plugin/core.py | 1786 +++++++++++++++++ compare-plugin/input/DefaultThresholds.json | 331 +++ compare-plugin/requirements.txt | 5 + compare-plugin/setup.py | 32 + compare-plugin/setup.sh | 31 + .../templates/Cisco-AppDynamics.png | Bin 0 -> 6328 bytes compare-plugin/templates/index.html | 78 + compare-plugin/test.py | 1751 ++++++++++++++++ compare-plugin/test1.py | 1786 +++++++++++++++++ 12 files changed, 5864 insertions(+) create mode 100644 compare-plugin/README.md create mode 100644 compare-plugin/__init__.py create mode 100644 compare-plugin/config.json create mode 100644 compare-plugin/core.py create mode 100644 compare-plugin/input/DefaultThresholds.json create mode 100644 compare-plugin/requirements.txt create mode 100644 compare-plugin/setup.py create mode 100755 compare-plugin/setup.sh create mode 100644 compare-plugin/templates/Cisco-AppDynamics.png create mode 100644 compare-plugin/templates/index.html create mode 100644 compare-plugin/test.py create mode 100644 compare-plugin/test1.py diff --git a/compare-plugin/README.md b/compare-plugin/README.md new file mode 100644 index 0000000..d938d71 --- /dev/null +++ b/compare-plugin/README.md @@ -0,0 +1,54 @@ +# CompareResults + +The configuration assessment tool (CAT) see [here](https://github.com/Appdynamics/config-assessment-tool) provides metrics on how well your applications are instrumented based on some of the field best practices. + +The CompareResults project piggy backs on to the output of the CAT, by allowing us to compare previous output against current output for APM only - these are workbooks ending with "-MaturityAssessment-apm.xlsx" + +## Requirements + +- Python 3.x + +# Setup! + +## Setup Instructions + +1. Unzip the `CompareResults` folder. + +2. On mac - open a terminal and navigate to the `CompareResults` directory: + cd path/to/unzipped/CompareResults + +3. Run the setup script using bash: + ./setup.sh + +4. After the bash script has complete and if all modules have been installed - run the following commands 1 after the other: + source venv/bin/activate + python3 compare_results/core.py + +5. The UI should automatically launch with an address of: http://127.0.0.1:5000/ - see considerations for upload. + - The only CAT report we can compare at this time is the APM output - ending with "-MaturityAssessment-apm.xlsx" + - The previous and current APM report has to be from the same controller - otherwise the script will terminate + - For best results ensure the previous APM report is dated before the Current APM report + + + +## If bash will not run: + +- chmod +x setup.sh + +## Module Not Found Errors +Modules should be installed as part of setup.sh, however, if you get Module Not Found Errors when running core.py (Error: ModuleNotFoundError: No module named 'openpyxl') you will have to install each Module. + +Below is a list of the modules needed: +- Flask +- pandas +- openpyxl +- python-pptx + +Install Module as follows: +- pip3 install <> or pip install <> +- Example if you receive: Error: ModuleNotFoundError: No module named 'openpyxl' - enter pip3 install openpyxl + + +To help with a successful comparison, see below: +1. Only one workbook "{jobName}-MaturityAssessment-apm.xlsx" can be compared for now +2. The xlsx files to be compared have to be from the same controller \ No newline at end of file diff --git a/compare-plugin/__init__.py b/compare-plugin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compare-plugin/config.json b/compare-plugin/config.json new file mode 100644 index 0000000..6b6d0d0 --- /dev/null +++ b/compare-plugin/config.json @@ -0,0 +1,10 @@ +{ + "upload_folder": "uploads", + "result_folder": "results", + "previous_file": "previous.xlsx", + "current_file": "current.xlsx", + "output_file": "comparison_result.xlsx", + "previous_sum_file": "previous_sum.xlsx", + "current_sum_file": "current_sum.xlsx", + "comparison_sum_file": "comparison_sum.xlsx" +} diff --git a/compare-plugin/core.py b/compare-plugin/core.py new file mode 100644 index 0000000..9f588b2 --- /dev/null +++ b/compare-plugin/core.py @@ -0,0 +1,1786 @@ +import os +import json +import sys +import logging +import webbrowser +from flask import Flask, request, send_file, render_template +import openpyxl +from openpyxl.styles import PatternFill, Font +from openpyxl.utils.dataframe import dataframe_to_rows +from openpyxl import load_workbook +import pandas as pd +from copy import copy +from pptx import Presentation +from pptx.util import Inches, Pt +from pptx.enum.text import PP_ALIGN +from pptx.dml.color import RGBColor +import xlwings as xw + +app = Flask(__name__) + +def save_workbook(filepath): + """Open and save the workbook to ensure formulas are recalculated.""" + # Open the workbook + app = xw.App(visible=False) # Set visible=False to avoid showing the Excel window + wb = app.books.open(filepath) + + # Save the workbook + wb.save() + + # Close the workbook + wb.close() + + # Quit the application + app.quit() + +def process_files(previous_file_path, current_file_path): + # Save the workbooks to trigger formula recalculation + save_workbook(previous_file_path) + save_workbook(current_file_path) + + # Continue with your comparison logic + compare_files_summary(previous_file_path, current_file_path, 'comparison_summary.xlsx') + +# Load configuration from JSON file +def load_config(): + # Determine the current script directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct the full path to the config.json file + config_path = os.path.join(script_dir, 'config.json') + + if not os.path.exists(config_path): + raise FileNotFoundError(f"Config file not found: {config_path}") + + with open(config_path) as f: + config = json.load(f) + + # Convert relative paths to absolute paths + config['upload_folder'] = os.path.join(script_dir, config.get('upload_folder', 'uploads')) + config['result_folder'] = os.path.join(script_dir, config.get('result_folder', 'results')) + + return config + +# Load the configuration +config = load_config() + +# Configure upload and result folders from config +UPLOAD_FOLDER = config['upload_folder'] +RESULT_FOLDER = config['result_folder'] + +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['RESULT_FOLDER'] = RESULT_FOLDER +logging.basicConfig(level=logging.DEBUG) + +# Ensure folders exist +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) +os.makedirs(app.config['RESULT_FOLDER'], exist_ok=True) + +def check_controllers_match(previous_file_path, current_file_path): + # Load the previous and current workbooks + previous_workbook = pd.read_excel(previous_file_path, sheet_name='Analysis') + current_workbook = pd.read_excel(current_file_path, sheet_name='Analysis') + + # Extract the 'controller' column from both workbooks and strip whitespaces + previous_controllers = previous_workbook['controller'].dropna().str.strip().unique() + current_controllers = current_workbook['controller'].dropna().str.strip().unique() + + # Log the exact controller values for debugging + logging.debug(f"Previous controller(s): {previous_controllers}") + logging.debug(f"Current controller(s): {current_controllers}") + + # Check if the controllers match + if not (len(previous_controllers) == 1 and len(current_controllers) == 1 and previous_controllers[0] == current_controllers[0]): + logging.error(f"Controllers do not match. Previous controller: {previous_controllers}, Current controller: {current_controllers}") + return False + + return True + +def generate_powerpoint_from_analysis(comparison_result_path, powerpoint_output_path): + logging.debug("Generating PowerPoint presentation...") + + try: + # Create a PowerPoint presentation + prs = Presentation() + slide_layout_title = prs.slide_layouts[0] # Title slide layout + slide_layout_content = prs.slide_layouts[5] # Title and Content layout + + # Slide 1: Title slide with "CAT Compare" + slide = prs.slides.add_slide(slide_layout_title) + title_shape = slide.shapes.title + title_shape.text = "CAT Compare" + + # Slide 2: Content from 'Summary' tab in table format + summary_df = pd.read_excel(comparison_result_path, sheet_name='Summary') + logging.debug("Loaded Summary sheet successfully.") + logging.debug(f"Summary DataFrame head:\n{summary_df.head()}") + + # Add a new slide for the Summary content + slide = prs.slides.add_slide(slide_layout_content) + title_shape = slide.shapes.title + title_shape.text = "Summary Tab" + + # Add a table for the summary data + rows, cols = summary_df.shape + table = slide.shapes.add_table(rows + 1, cols, Inches(0.5), Inches(1.5), Inches(8), Inches(5)).table + + # Set the column headers (from DataFrame columns) + for col_idx, column in enumerate(summary_df.columns): + table.cell(0, col_idx).text = str(column) + table.cell(0, col_idx).text_frame.paragraphs[0].font.size = Pt(12) + + # Add the data rows + for row_idx, row in summary_df.iterrows(): + for col_idx, value in enumerate(row): + table.cell(row_idx + 1, col_idx).text = str(value) + table.cell(row_idx + 1, col_idx).text_frame.paragraphs[0].font.size = Pt(12) + + # Slide 3: The current slide with Assessment comparison + df = pd.read_excel(comparison_result_path, sheet_name='Analysis') + logging.debug("Loaded Analysis sheet successfully.") + logging.debug(f"DataFrame head:\n{df.head()}") + + # Initialize counts + results = {} + columns = [ + 'AppAgentsAPM', 'MachineAgentsAPM', 'BusinessTransactionsAPM', + 'BackendsAPM', 'OverheadAPM', 'ServiceEndpointsAPM', + 'ErrorConfigurationAPM', 'HealthRulesAndAlertingAPM', + 'DataCollectorsAPM', 'DashboardsAPM', 'OverallAssessment' + ] + + total_applications = len(df) # Total number of applications + + for col in columns: + # Extract upgrade and downgrade information + df[col] = df[col].astype(str) + upgraded_count = df[col].str.contains('upgraded', case=False, na=False).sum() + downgraded_count = df[col].str.contains('downgraded', case=False, na=False).sum() + + # Store results + results[col] = { + 'upgraded': upgraded_count, + 'downgraded': downgraded_count + } + logging.debug(f"Column: {col}, Upgraded: {upgraded_count}, Downgraded: {downgraded_count}") + + # Add the third slide for Assessment Comparison + slide = prs.slides.add_slide(slide_layout_content) + title_shape = slide.shapes.title + title_shape.text = "Assessment Comparison - Status" + + textbox = slide.shapes.add_textbox(Inches(0.5), Inches(1.0), Inches(8), Inches(0.5)) + text_frame = textbox.text_frame + p = text_frame.add_paragraph() + p.text = f"Total number of Applications Compared: {total_applications}" + p.font.size = Pt(14) + text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER + textbox.left = Inches(0.5) + textbox.width = Inches(8) + + # Add table to the slide + rows = len(columns) + 1 + cols = 3 # Total, Upgraded, Downgraded columns + table = slide.shapes.add_table(rows, cols, Inches(0.5), Inches(2.0), Inches(8), Inches(4)).table + + # Set table headers + table.cell(0, 0).text = 'Metric' + table.cell(0, 1).text = 'Maturity Increase' + table.cell(0, 2).text = 'Maturity Decrease' + + # Set font size for headers + for cell in table.rows[0].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Populate the table + for i, col in enumerate(columns, start=1): + table.cell(i, 0).text = col + table.cell(i, 1).text = f"{results[col]['upgraded'] / total_applications * 100:.2f}%" + table.cell(i, 2).text = f"{results[col]['downgraded'] / total_applications * 100:.2f}%" + + for cell in table.rows[i].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Save the presentation + prs.save(powerpoint_output_path) + logging.debug(f"PowerPoint saved to {powerpoint_output_path}.") + + except Exception as e: + logging.error(f"Error generating PowerPoint: {e}", exc_info=True) + raise + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/upload', methods=['POST']) +def upload(): + logging.debug("Request files: %s", request.files) + + if 'previous_file' not in request.files or 'current_file' not in request.files: + logging.error("No file part") + return render_template('index.html', message="Error: No file part was uploaded."), 400 + + previous_file = request.files.get('previous_file') + current_file = request.files.get('current_file') + + if not previous_file or previous_file.filename == '': + logging.error("No selected file for previous") + return render_template('index.html', message="Error: No previous file was selected."), 400 + + if not current_file or current_file.filename == '': + logging.error("No selected file for current") + return render_template('index.html', message="Error: No current file was selected."), 400 + + previous_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous.xlsx') + current_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current.xlsx') + output_file_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_result.xlsx') + previous_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous_sum.xlsx') + current_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current_sum.xlsx') + comparison_sum_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_sum.xlsx') + powerpoint_output_path = os.path.join(app.config['RESULT_FOLDER'], 'Analysis_Summary.pptx') + + try: + # Save the uploaded files + previous_file.save(previous_file_path) + current_file.save(current_file_path) + + # Automatically save the workbooks to recalculate formulas + save_workbook(previous_file_path) + save_workbook(current_file_path) + + # Check if controllers match + if not check_controllers_match(previous_file_path, current_file_path): + logging.error("Controllers do not match.") + return render_template('index.html', message="Error: The controllers in the two files do not match. Please upload files from the same controller."), 400 + + # Proceed with comparison... + create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path) + compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path) + compare_files_other_sheets(previous_file_path, current_file_path, output_file_path) + copy_summary_to_result(comparison_sum_path, output_file_path) + generate_powerpoint_from_analysis(output_file_path, powerpoint_output_path) + + return render_template( + 'index.html', + message=( + f"Comparison completed successfully. " + f"You can download the results from your browser by clicking " + f"here " + f"and the PowerPoint summary by clicking " + f"here.
" + f"
Click here to return to the home page" + ) + ) + + except Exception as e: + logging.error(f"Error during file upload or comparison: {e}", exc_info=True) + return render_template('index.html', message="Error during file upload or comparison"), 500 + +@app.route('/download/') +def download_file(filename): + # Provide a download link for the output file + return send_file(os.path.join(app.config['RESULT_FOLDER'], filename), as_attachment=True) + + +# Define color fills for Excel cells +red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid') +green_fill = PatternFill(start_color='00FF00', end_color='00FF00', fill_type='solid') +added_fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') + +# Helper function to find column index by name +def get_key_column(sheet, key_name): + for i, cell in enumerate(sheet[1], 1): + if cell.value == key_name: + return i + return None + +# Function to create summary workbooks +def create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path): + try: + wb_previous = load_workbook(previous_file_path, data_only=True) + wb_current = load_workbook(current_file_path, data_only=True) + + if 'Summary' not in wb_previous.sheetnames or 'Summary' not in wb_current.sheetnames: + logging.error("'Summary' sheet is missing in one of the files.") + return + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + + # Create new workbooks for the summaries + wb_previous_sum = openpyxl.Workbook() + wb_current_sum = openpyxl.Workbook() + + ws_previous_sum = wb_previous_sum.active + ws_current_sum = wb_current_sum.active + + ws_previous_sum.title = 'Summary' + ws_current_sum.title = 'Summary' + + # Copy data from original workbooks to summary workbooks as values only + for row in ws_previous.iter_rows(values_only=True): + ws_previous_sum.append(row) + for row in ws_current.iter_rows(values_only=True): + ws_current_sum.append(row) + + # Save the cleaned-up summary workbooks + wb_previous_sum.save(previous_sum_path) + wb_current_sum.save(current_sum_path) + + except Exception as e: + logging.error(f"Error in create_summary_workbooks: {e}", exc_info=True) + raise + + +# Function to compare 'Summary' sheet and save to a new workbook +def compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path): + try: + # Load the previous_sum and current_sum Excel files + wb_previous = load_workbook(previous_sum_path, data_only=True) + wb_current = load_workbook(current_sum_path, data_only=True) + wb_output = openpyxl.Workbook() + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + ws_output = wb_output.active + ws_output.title = 'Summary' + + # Debugging: Print sheet names and some data from the 'Summary' sheet + print("Previous Workbook Sheets:", wb_previous.sheetnames) + print("Current Workbook Sheets:", wb_current.sheetnames) + print("Example data from 'Summary' sheet in Previous Workbook (1,1):", ws_previous.cell(row=1, column=1).value) + print("Example data from 'Summary' sheet in Current Workbook (1,1):", ws_current.cell(row=1, column=1).value) + + logging.debug(f"Processing sheet: 'Summary'") + + compare_summary(ws_previous, ws_current, ws_output) + + # Save the workbook after all modifications have been completed + wb_output.save(comparison_sum_path) + logging.debug(f"Summary comparison saved to: {comparison_sum_path}") + + except Exception as e: + logging.error(f"Error in compare_files_summary: {e}", exc_info=True) + raise + + +# Function to compare summaries of both sheets +def compare_summary(ws_previous, ws_current, ws_output): + from openpyxl.styles import PatternFill + + # Define fill styles + red_fill = PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid") + green_fill = PatternFill(start_color="00FF00", end_color="00FF00", fill_type="solid") + + for row in ws_previous.iter_rows(min_row=1, min_col=1, max_col=ws_previous.max_column, max_row=ws_previous.max_row): + for cell in row: + prev_cell = ws_previous.cell(row=cell.row, column=cell.column) + curr_cell = ws_current.cell(row=cell.row, column=cell.column) + output_cell = ws_output.cell(row=cell.row, column=cell.column) + + prev_value = prev_cell.value + curr_value = curr_cell.value + + if prev_value is None: + prev_value = '' + if curr_value is None: + curr_value = '' + + logging.debug(f"Comparing cell ({cell.row},{cell.column}): Previous Value: {prev_value}, Current Value: {curr_value}") + + if prev_value != curr_value: + if isinstance(prev_value, (int, float)) and isinstance(curr_value, (int, float)): + if curr_value > prev_value: + output_cell.fill = green_fill + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.value = prev_value + + logging.debug(f"Cell ({cell.row},{cell.column}) updated to: {output_cell.value}") + + +def eval_formula(ws, cell): + """ Helper function to evaluate a cell's formula and return the result. """ + try: + if cell.data_type == 'f': + # Create a temporary workbook to evaluate the formula + temp_wb = openpyxl.Workbook() + temp_ws = temp_wb.active + temp_ws.cell(row=1, column=1).value = cell.value + + # Copy relevant data from the original sheet + for row in range(1, ws.max_row + 1): + for col in range(1, ws.max_column + 1): + temp_ws.cell(row=row + 1, column=col).value = ws.cell(row=row, column=col).value + + # Save and reopen to evaluate formulas + temp_file = "temp.xlsx" + temp_wb.save(temp_file) + temp_wb.close() + + temp_wb = openpyxl.load_workbook(temp_file) + temp_ws = temp_wb.active + eval_result = temp_ws['A1'].value + temp_wb.close() + + return eval_result + except Exception as e: + logging.error(f"Error evaluating formula in cell {cell.coordinate}: {e}", exc_info=True) + return None + +# Function to copy the Summary sheet from comparison_sum to comparison_result +def copy_summary_to_result(comparison_sum_path, output_file_path): + try: + # Load the comparison_sum and output workbooks + wb_comparison_sum = load_workbook(comparison_sum_path) + wb_output = load_workbook(output_file_path) + + # Get the Summary sheet from comparison_sum + ws_comparison_sum = wb_comparison_sum['Summary'] + + # If the Summary sheet already exists in output, delete it + if 'Summary' in wb_output.sheetnames: + del wb_output['Summary'] + + # Create a new Summary sheet in the output workbook + ws_output = wb_output.create_sheet('Summary', 0) # Insert Summary as the first sheet + + # Copy data and formatting from the comparison_sum Summary sheet to the output Summary sheet + for row in ws_comparison_sum.iter_rows(): + for cell in row: + new_cell = ws_output.cell(row=cell.row, column=cell.column, value=cell.value) + + # Copy individual style attributes + if cell.has_style: + new_cell.font = copy(cell.font) + new_cell.border = copy(cell.border) + new_cell.fill = copy(cell.fill) + new_cell.number_format = cell.number_format + new_cell.protection = copy(cell.protection) + new_cell.alignment = copy(cell.alignment) + + # Define header colors for Bronze, Silver, Gold, and Platinum + header_colors = { + 'B1': 'cd7f32', # Bronze + 'C1': 'c0c0c0', # Silver + 'D1': 'ffd700', # Gold + 'E1': 'e5e4e2' # Platinum + } + + # Apply colors to the headers in the first row + for col in header_colors: + cell = ws_output[col] + cell.fill = PatternFill(start_color=header_colors[col], end_color=header_colors[col], fill_type="solid") + cell.font = Font(bold=True, color="000000") + + # Save the output workbook + wb_output.save(output_file_path) + logging.debug("Summary sheet copied to the final comparison result and placed as the first sheet with highlighted headers.") + + except Exception as e: + logging.error(f"Error in copy_summary_to_result: {e}", exc_info=True) + raise + +# Function to compare files for all other sheets +def compare_files_other_sheets(previous_file_path, current_file_path, output_file_path): + try: + wb_previous = load_workbook(previous_file_path) + wb_current = load_workbook(current_file_path) + + for sheet_name in wb_current.sheetnames: + if sheet_name in wb_previous.sheetnames: + ws_previous = wb_previous[sheet_name] + ws_current = wb_current[sheet_name] + + logging.debug(f"Processing sheet: {sheet_name}") + + if sheet_name == 'Analysis': + compare_analysis(ws_previous, ws_current) + elif sheet_name == 'AppAgentsAPM': + compare_appagentsapm(ws_previous, ws_current) + elif sheet_name == 'MachineAgentsAPM': + compare_machineagentsapm(ws_previous, ws_current) + elif sheet_name == 'BusinessTransactionsAPM': + compare_businesstransactionsapm(ws_previous, ws_current) + elif sheet_name == 'BackendsAPM': + compare_backendsapm(ws_previous, ws_current) + elif sheet_name == 'OverheadAPM': + compare_overheadapm(ws_previous, ws_current) + elif sheet_name == 'ServiceEndpointsAPM': + compare_serviceendpointsapm(ws_previous, ws_current) + elif sheet_name == 'ErrorConfigurationAPM': + compare_errorconfigurationapm(ws_previous, ws_current) + elif sheet_name == 'HealthRulesAndAlertingAPM': + compare_healthrulesandalertingapm(ws_previous, ws_current) + elif sheet_name == 'DataCollectorsAPM': + compare_datacollectorsapm(ws_previous, ws_current) + elif sheet_name == 'DashboardsAPM': + compare_dashboardsapm(ws_previous, ws_current) + elif sheet_name == 'OverallAssessmentAPM': + compare_overallassessmentapm(ws_previous, ws_current) + elif sheet_name == 'Summary': + continue + else: + logging.warning(f"No comparison function defined for sheet: {sheet_name}") + + wb_current.save(output_file_path) + logging.debug(f"Comparison results saved to: {output_file_path}") + + except Exception as e: + logging.error(f"Error in compare_files_other_sheets: {e}", exc_info=True) + raise + +def compare_appagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'metricLimitNotHit': None, + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + if column == 'metricLimitNotHit': + # Handle boolean logic for metricLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_appagentsapm: {e}", exc_info=True) + raise + +def compare_machineagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None, + 'percentAgentsInstalledAlongsideAppAgents': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle numeric logic for percentage columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_machineagentsapm: {e}", exc_info=True) + raise + +def compare_datacollectorsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfDataCollectorFieldsConfigured': None, + 'numberOfDataCollectorFieldsCollectedInSnapshots': None, + 'numberOfDataCollectorFieldsCollectedInAnalytics': None, + 'biqEnabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'biqEnabled': + # Handle boolean logic for biqEnabled + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_datacollectorsapm: {e}", exc_info=True) + raise + +def compare_backendsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentBackendsWithLoad': None, + 'backendLimitNotHit': None, + 'numberOfCustomBackendRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'backendLimitNotHit': + # Handle boolean logic for backendLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Increased)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Decreased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_backendsapm: {e}", exc_info=True) + raise + +def compare_overheadapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'developerModeNotEnabledForAnyBT': None, + 'findEntryPointsNotEnabled': None, + 'aggressiveSnapshottingNotEnabled': None, + 'developerModeNotEnabledForApplication': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle boolean logic for specified columns + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overheadapm: {e}", exc_info=True) + raise + +def compare_healthrulesandalertingapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfHealthRuleViolations': None, + 'numberOfDefaultHealthRulesModified': None, + 'numberOfActionsBoundToEnabledPolicies': None, + 'numberOfCustomHealthRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'numberOfHealthRuleViolations': + if curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + else: + # For other columns + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_healthrulesandalertingapm: {e}", exc_info=True) + raise + +def compare_errorconfigurationapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'successPercentageOfWorstTransaction': None, + 'numberOfCustomRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'successPercentageOfWorstTransaction': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + elif column == 'numberOfCustomRules': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_errorconfigurationapm: {e}", exc_info=True) + raise + +def compare_serviceendpointsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfCustomServiceEndpointRules': None, + 'serviceEndpointLimitNotHit': None, + 'percentServiceEndpointsWithLoadOrDisabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfCustomServiceEndpointRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'serviceEndpointLimitNotHit': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'percentServiceEndpointsWithLoadOrDisabled': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_serviceendpointsapm: {e}", exc_info=True) + raise + +def compare_dashboardsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfDashboards': None, + 'percentageOfDashboardsModifiedLast6Months': None, + 'numberOfDashboardsUsingBiQ': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_dashboardsapm: {e}", exc_info=True) + raise + +def compare_overallassessmentapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'percentageTotalPlatinum': None, + 'percentageTotalGoldOrBetter': None, + 'percentageTotalSilverOrBetter': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overallassessmentapm: {e}", exc_info=True) + raise + +# Function to compare 'Business Transactions' sheet +def compare_businesstransactionsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfBTs': None, + 'percentBTsWithLoad': None, + 'btLockdownEnabled': None, + 'numberCustomMatchRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfBTs': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if 201 <= prev_value_num <= 600: + if curr_value_num < prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + elif curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + + elif column == 'percentBTsWithLoad': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'btLockdownEnabled': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'numberCustomMatchRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_businesstransactionsapm: {e}", exc_info=True) + raise + +def compare_analysis(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'AppAgentsAPM': None, + 'MachineAgentsAPM': None, + 'BusinessTransactionsAPM': None, + 'BackendsAPM': None, + 'OverheadAPM': None, + 'ServiceEndpointsAPM': None, + 'ErrorConfigurationAPM': None, + 'HealthRulesAndAlertingAPM': None, + 'DataCollectorsAPM': None, + 'DashboardsAPM': None, + 'OverallAssessment': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + name_col_prev = get_key_column(ws_previous, 'name') + name_col_curr = get_key_column(ws_current, 'name') + + if name_col_prev is None or name_col_curr is None: + logging.error("The 'name' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Comparison logic based on ranking + ranking = {'bronze': 1, 'silver': 2, 'gold': 3, 'platinum': 4} + prev_rank = ranking.get(previous_value.lower(), 0) + curr_rank = ranking.get(current_value.lower(), 0) + + if curr_rank > prev_rank: + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Upgraded)" + elif curr_rank < prev_rank: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Downgraded)" + except ValueError: + logging.error(f"Invalid ranking value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_analysis: {e}", exc_info=True) + raise + +if __name__ == '__main__': + # Automatically open the default web browser to the correct URL + url = "http://127.0.0.1:5000" # This is the default URL where Flask serves + webbrowser.open(url) + + # Run the Flask app + app.run(debug=True) diff --git a/compare-plugin/input/DefaultThresholds.json b/compare-plugin/input/DefaultThresholds.json new file mode 100644 index 0000000..fdf462a --- /dev/null +++ b/compare-plugin/input/DefaultThresholds.json @@ -0,0 +1,331 @@ +{ + "version": "v1.5.9.9", + "apm": { + "AppAgentsAPM": { + "platinum": { + "percentAgentsLessThan1YearOld": 100, + "percentAgentsLessThan2YearsOld": 100, + "percentAgentsReportingData": 100, + "percentAgentsRunningSameVersion": 100, + "metricLimitNotHit": true + }, + "gold": { + "percentAgentsLessThan1YearOld": 80, + "percentAgentsLessThan2YearsOld": 80, + "percentAgentsReportingData": 80, + "percentAgentsRunningSameVersion": 80, + "metricLimitNotHit": true + }, + "silver": { + "percentAgentsLessThan1YearOld": 0, + "percentAgentsLessThan2YearsOld": 50, + "percentAgentsReportingData": 0, + "percentAgentsRunningSameVersion": 0, + "metricLimitNotHit": true + } + }, + "BusinessTransactionsAPM": { + "platinum": { + "numberCustomMatchRules": 3, + "btLockdownEnabled": true, + "percentBTsWithLoad": 90, + "numberOfBTs": 200 + }, + "gold": { + "numberCustomMatchRules": 1, + "btLockdownEnabled": false, + "percentBTsWithLoad": 75, + "numberOfBTs": 400 + }, + "silver": { + "numberCustomMatchRules": 0, + "btLockdownEnabled": false, + "percentBTsWithLoad": 0, + "numberOfBTs": 600 + } + }, + "MachineAgentsAPM": { + "platinum": { + "percentAgentsLessThan1YearOld": 100, + "percentAgentsLessThan2YearsOld": 100, + "percentAgentsReportingData": 100, + "percentAgentsRunningSameVersion": 100, + "percentAgentsInstalledAlongsideAppAgents": 100 + }, + "gold": { + "percentAgentsLessThan1YearOld": 80, + "percentAgentsLessThan2YearsOld": 80, + "percentAgentsReportingData": 80, + "percentAgentsRunningSameVersion": 80, + "percentAgentsInstalledAlongsideAppAgents": 80 + }, + "silver": { + "percentAgentsLessThan1YearOld": 0, + "percentAgentsLessThan2YearsOld": 50, + "percentAgentsReportingData": 0, + "percentAgentsRunningSameVersion": 0, + "percentAgentsInstalledAlongsideAppAgents": 0 + } + }, + "BackendsAPM": { + "platinum": { + "backendLimitNotHit": true, + "percentBackendsWithLoad": 75, + "numberOfCustomBackendRules": 1 + }, + "gold": { + "backendLimitNotHit": true, + "percentBackendsWithLoad": 60, + "numberOfCustomBackendRules": 0 + }, + "silver": { + "backendLimitNotHit": true, + "percentBackendsWithLoad": 0, + "numberOfCustomBackendRules": 0 + } + }, + "OverheadAPM": { + "platinum": { + "developerModeNotEnabledForAnyBT": true, + "developerModeNotEnabledForApplication": true, + "findEntryPointsNotEnabled": true, + "aggressiveSnapshottingNotEnabled": true + }, + "gold": { + "developerModeNotEnabledForAnyBT": true, + "developerModeNotEnabledForApplication": true, + "findEntryPointsNotEnabled": true, + "aggressiveSnapshottingNotEnabled": true + }, + "silver": { + "developerModeNotEnabledForAnyBT": true, + "developerModeNotEnabledForApplication": true, + "findEntryPointsNotEnabled": true, + "aggressiveSnapshottingNotEnabled": true + } + }, + "ServiceEndpointsAPM": { + "platinum": { + "serviceEndpointLimitNotHit": true, + "percentServiceEndpointsWithLoadOrDisabled": 50, + "numberOfCustomServiceEndpointRules": 1 + }, + "gold": { + "serviceEndpointLimitNotHit": true, + "percentServiceEndpointsWithLoadOrDisabled": 25, + "numberOfCustomServiceEndpointRules": 0 + }, + "silver": { + "serviceEndpointLimitNotHit": true, + "percentServiceEndpointsWithLoadOrDisabled": 0, + "numberOfCustomServiceEndpointRules": 0 + } + }, + "ErrorConfigurationAPM": { + "platinum": { + "numberOfCustomRules": 1, + "successPercentageOfWorstTransaction": 80 + }, + "gold": { + "numberOfCustomRules": 0, + "successPercentageOfWorstTransaction": 80 + }, + "silver": { + "numberOfCustomRules": 0, + "successPercentageOfWorstTransaction": 50 + } + }, + "HealthRulesAndAlertingAPM": { + "platinum": { + "numberOfHealthRuleViolations": 10, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 5, + "numberOfDefaultHealthRulesModified": 2 + }, + "gold": { + "numberOfHealthRuleViolations": 20, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 2, + "numberOfDefaultHealthRulesModified": 1 + }, + "silver": { + "numberOfHealthRuleViolations": 50, + "numberOfActionsBoundToEnabledPolicies": 0, + "numberOfCustomHealthRules": 0, + "numberOfDefaultHealthRulesModified": 0 + } + }, + "DataCollectorsAPM": { + "platinum": { + "numberOfDataCollectorFieldsConfigured": 5, + "numberOfDataCollectorFieldsCollectedInSnapshots": 5, + "numberOfDataCollectorFieldsCollectedInAnalytics": 5, + "biqEnabled": true + }, + "gold": { + "numberOfDataCollectorFieldsConfigured": 2, + "numberOfDataCollectorFieldsCollectedInSnapshots": 2, + "numberOfDataCollectorFieldsCollectedInAnalytics": 2, + "biqEnabled": false + }, + "silver": { + "numberOfDataCollectorFieldsConfigured": 0, + "numberOfDataCollectorFieldsCollectedInSnapshots": 0, + "numberOfDataCollectorFieldsCollectedInAnalytics": 0, + "biqEnabled": false + } + }, + "DashboardsAPM": { + "platinum": { + "numberOfDashboards": 5, + "percentageOfDashboardsModifiedLast6Months": 100, + "numberOfDashboardsUsingBiQ": 1 + }, + "gold": { + "numberOfDashboards": 1, + "percentageOfDashboardsModifiedLast6Months": 10, + "numberOfDashboardsUsingBiQ": 0 + }, + "silver": { + "numberOfDashboards": 0, + "percentageOfDashboardsModifiedLast6Months": 0, + "numberOfDashboardsUsingBiQ": 0 + } + }, + "OverallAssessmentAPM": { + "platinum": { + "percentageTotalPlatinum": 50, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 100 + }, + "gold": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 90 + }, + "silver": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 0, + "percentageTotalSilverOrBetter": 80 + } + } + }, + "brum": { + "NetworkRequestsBRUM": { + "platinum": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 5, + "hasBtCorrelation": true, + "hasCustomEventServiceIncludeRule": true + }, + "gold": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 3, + "hasBtCorrelation": false, + "hasCustomEventServiceIncludeRule": false + }, + "silver": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 2, + "hasBtCorrelation": false, + "hasCustomEventServiceIncludeRule": false + } + }, + "HealthRulesAndAlertingBRUM": { + "platinum": { + "numberOfHealthRuleViolations": 10, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 5 + }, + "gold": { + "numberOfHealthRuleViolations": 20, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 2 + }, + "silver": { + "numberOfHealthRuleViolations": 50, + "numberOfActionsBoundToEnabledPolicies": 0, + "numberOfCustomHealthRules": 0 + } + }, + "OverallAssessmentBRUM": { + "platinum": { + "percentageTotalPlatinum": 50, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 100 + }, + "gold": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 90 + }, + "silver": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 0, + "percentageTotalSilverOrBetter": 80 + } + } + }, + "mrum": { + "NetworkRequestsMRUM": { + "platinum": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 5, + "hasBtCorrelation": true, + "hasCustomEventServiceIncludeRule": true + }, + "gold": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 3, + "hasBtCorrelation": false, + "hasCustomEventServiceIncludeRule": false + }, + "silver": { + "collectingDataPastOneDay": true, + "networkRequestLimitNotHit": true, + "numberCustomMatchRules": 2, + "hasBtCorrelation": false, + "hasCustomEventServiceIncludeRule": false + } + }, + "HealthRulesAndAlertingMRUM": { + "platinum": { + "numberOfHealthRuleViolations": 10, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 5 + }, + "gold": { + "numberOfHealthRuleViolations": 20, + "numberOfActionsBoundToEnabledPolicies": 1, + "numberOfCustomHealthRules": 2 + }, + "silver": { + "numberOfHealthRuleViolations": 50, + "numberOfActionsBoundToEnabledPolicies": 0, + "numberOfCustomHealthRules": 0 + } + }, + "OverallAssessmentMRUM": { + "platinum": { + "percentageTotalPlatinum": 50, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 100 + }, + "gold": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 50, + "percentageTotalSilverOrBetter": 90 + }, + "silver": { + "percentageTotalPlatinum": 0, + "percentageTotalGoldOrBetter": 0, + "percentageTotalSilverOrBetter": 80 + } + } + } +} \ No newline at end of file diff --git a/compare-plugin/requirements.txt b/compare-plugin/requirements.txt new file mode 100644 index 0000000..e32d40a --- /dev/null +++ b/compare-plugin/requirements.txt @@ -0,0 +1,5 @@ +Flask>=2.3.2 +pandas>=1.5.3 +openpyxl>=3.1.2 +python-pptx>=0.6.21 +xlwings>=0.28.0 \ No newline at end of file diff --git a/compare-plugin/setup.py b/compare-plugin/setup.py new file mode 100644 index 0000000..7aff5ef --- /dev/null +++ b/compare-plugin/setup.py @@ -0,0 +1,32 @@ +from setuptools import setup, find_packages + +setup( + name="CompareResults", + version="0.1.0", + packages=find_packages(), + include_package_data=True, + install_requires=[ + "Flask>=2.3.2", + "pandas>=1.5.3", + "openpyxl>=3.1.2", + "python-pptx>=0.6.21", + ], + entry_points={ + "console_scripts": [ + "compare-results=compare_results.core:main", + ], + }, + author="Your Name", + author_email="your.email@example.com", + description="A web app to compare Excel results and generate analysis summaries in PowerPoint.", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + # url="https://github.com/yourusername/CompareResults", + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + python_requires='>=3.6', +) + diff --git a/compare-plugin/setup.sh b/compare-plugin/setup.sh new file mode 100755 index 0000000..7aa3739 --- /dev/null +++ b/compare-plugin/setup.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check if Python 3 is installed +if command_exists python3; then + echo "Python 3 is installed." +else + echo "Python 3 is not installed. Please install Python 3 before proceeding." + exit 1 +fi + +# Create a virtual environment +echo "Creating a virtual environment..." +python3 -m venv venv + +# Activate the virtual environment +echo "Activating the virtual environment..." +source venv/bin/activate + +# Install the required packages +echo "Installing required Python packages..." +pip install -r requirements.txt + +echo "Setup is complete. You can now run the script using:" +echo " source venv/bin/activate" +echo " python3 compare_results/core.py" + diff --git a/compare-plugin/templates/Cisco-AppDynamics.png b/compare-plugin/templates/Cisco-AppDynamics.png new file mode 100644 index 0000000000000000000000000000000000000000..013cd93ee7f71435777e7a6b080289cfefc5a116 GIT binary patch literal 6328 zcmXX~cRXCr*Crvl=z;_hU68L5QA70JR_|pA(PFLMdx>uKUe{s?!74$tV96?Bb)rRy z)rk_`_4~Z@$K09coI5kmx#!I1o)f2|rA$W5NQ{GnL#C>tpofElyNDed6F$QBR%c4d z*aw4`qOq60yMvdHjVBOC&feV?$g1jU;|SCP+SvPj90p3^;5;!^RgeSt&i}EH_FPxV z)cTCfj@yoP5SL!3-KhIaIVK?&#+9<2XjCp%I7FQyg*!|gD-mYAWn8MoYS@4EEI92w6ip~oCHywxqPTbA)^2PBcQdpNNMDp%{_42<}l;Cg`Duh_r zYUu>^<}y%QhT!Vv`Y41A7kgTq13X8L;Y^kDlC`E6oa^pHmzZ&ydz?_L$m_uKr;AC- z702Wf`$m9l(>+`j%`#&7cl~=&h<5NzpRV{VTcP>Xod$-9v&iZ$HY8yj%MPcf!w6C9 z$&$_@rwLr(Dk7Tk$8Hs>FI&HMhGaz2aTa}#{7L_w6RWxUmCrn0gA=k)-w7H@Gl)a9W$si8&kiIKf;th#8q!}%eD{YF;~f;FPF59T zeT~Rz4kY|`Oq7`p6LEEo)YRbz#k)ai$NNlB0=_b&LBY|n%ACExXA<{>YD?J9kT8k2 z+nbKlloQV!J^-3&!-f3y}?S=(G&tI=O>RfgoHf=aoMk?Fg%3S_2ClP>m z)SEw=%Fki$DU<#O2lqlOlL#+N0Z3EPT9AiC@XCk8_9~(SkS5Ba!SNeDw9g$@TLP-; z0s#tDI`buH4Y<=2(i@;G!Rv9XytRl^!gFO{->x;4o*lQ*Oap&~7 z?bl`(!_p{cMv}@dAIq3uW~*&4=#?{b2mN#W>pBwu-iioXLMR^X%&thjFY=2LXI(qG ztRxGFCaCvaMUx9G>ZI)eU(r7c{gPSNE9;o!kJtEyhheykYqO$Df>v7`VPuYSeQu8; zgKW-wKRr^YM;gcoo&>wh?p`gIhwC964D{&ubVFt&@-9p3E;rhDJNZ(hKm43gS`=fs zWB@J~!Mk5XH2#^@hUYc@M`M^D<95;lKPM%2nYXX9qt~LHBun>9mXrldJy7eS9*p?; z4I@=^&68DqAZG%#WcGcv@F^zB;pM5HZKLR^7rK^@w?>4?y!)NBDDdQXT=6-TA1%h=IT>=)h>AW zRa>g~`VrL=32uGe0kF-JFH_~rV&o63HNXmBYT}bC>gK(m32R|bey$axuP+#~Nxa|Y z0g{RL7{kd_$5^DuY`^^XXlO~??Y}niI{ZTVoQKW;CoqEyiH-N(RCdMBZ`UqA5i|q& z^w!|h3{!>Nnol(C!5LychX>nD>LZObmmRLQ0wFii9-+$rp{kLa}spdVAV+!KvlAp)o2oz4lcK3e2#tnS=Xn3Hb3D6?()Fn}I878)V+-*|1Lt7gU5?UilsC*-HQ4Pj@=F~P9}-ck&0!&Tt6*B%uw zy0r(_U@4VRZ7EDro1lYStdIfMtYBjHogeulTBikVu4vUZK}{Eu#N9bF#Ge}5KM@l{ z{WMRmj+E@iMJ7VL{#_)th9b*_VS%GvRVVYBQl`XSg^x>&iXY5xd-;t3jch}sWWF$> z=MXqHt|Ggm=pp%vHRsP70jN)*1(h1~nHQ67nGrwVtjkm}qCZ2wLu&K5Yd8m>pwbX> zjBNzJ+r(jk(;y&aoqv4aVhJ*)WGE~kY8f3wvaWxjF>m_Cqxt3JdYF?i#k`&wFaxly zO2EYQvt#ivhRU!cIo33=B{_h?-TX{9;)CBvf8|0#TP;t@4(o;Ez{a%Nf(m7w-|UlH zLB2Cne1e38xN$-GPb9vt*mMuB0%?yZjgwM28$>;pL%28j(hok~1>|%sQlAUdePoJ= z9v+&RJ{*o9pFyW=zWyFm3Ua!9LPL3_fFOS??~zy#M(R?Mrva|sIS0d-lYEyykd}00 z?pjr!gEF7ba3ne!f#1&ue6^jNjw?#7s;a`z^`31th68bfiQ0bDx3N$YAr)LU^w<`y z)M(&!n)?CDi3?w@%j=ys{#Y+KGcGGbuBU~gBt@UN)`fC)4?)-jDVp;otBLx~sg$2M zEkkAo7|BY7UhcTixK`*%8EF!dzmE6LJ)edz_y@}PLXVPS>ArKFp@sIAg5qM`b3!4* zA^sfGvS!qGKFEXXVy`X63QF1nJobZktH_~WpHyMTfgehw9%`;E`sn~u)%(U*O@9~+ zXhI7g*C z=E;3@>`Ij;z^m6f?NoEQfY?t`Ek`MLR*z71ys;c@)Y#!+39=%^Ap!hX8V{e^&vl_T zG?o}>aJG%>PZ|7JBP5Hs2~dC0PTn`*@a#1eGkn3DNJ{DbTX#zOCL()dnIY!X$Fz`z zmS0z~k~6`)NC_c(oj4JOmZ6GfxLkFhCdSPEz%x};k6!g~3gnc)Dx#^tU%6G&mlCK* zns4|cySa*NASEL)v$irmIK!b71~N|;Rmye>xl@{GP3m}*`^x$~L%HmAf+$@MgmA9m~D=R-(@5 z<;7xEds|E{Kbi8OZ8|PH94bQD3t-vcVVE(-gG_XY)qy;n=Ts)#yjCpa!3b+RV=?AH z%U1qyK^eOEM3{wxrM6;>CgzlBZNzfmcoe@F@F{l~Y*t(X7T~vPC4A;wD5aiS_gJaK zMlzB_$lN)$V*dh-uNy_1R3bcmX`Ep;$#eX*;aAXYd-H%m-2#R`QFnzfdysniB3xfA z?Yb?NZ%V078Hb z4&E`HQGPb)-uf1d!JWh8AU5 zDU?t^(qU3M<`dT!xkRv5y0?A+P#?l1W*k!_xlHCJQX0vIj?t{~#-xL`dZ9_%epI;S z9u_Wd+(t&4L`mm8nnj$BEUz*M9}XF`NEq#G6}YWGnUQ*(N4n)QQU+F2LR-F|8KU5W zfb!tKg6h$9=*Z50I$AMmpk3HTHu^lO@I@3LfQ?i>ql!4uLGV8X#lqf=2Q=GN8Idn8 zr5NWqsW7eHU|?^eqUOXODP6Ik#u-}wE>W+5vp6pn7xNCO3z_3)JCezNFbYpQt%=!I zhHJ)B8Gp04hl9@3Y%Tl!-F5n75X9E%a1SW8&l|q|q}Tx(Mh@oPSKcYh~c#YB*xeRiAo_^I5*p~MWV4^<82g#?%XP-XRr^x*A zRkQoC_|cG-s3pe>cMj4V%p~__9WE@gxX2;Avx!dNiNCwEX4Rb7EjVwRqwgNP zCRW|Y%glCU#@y;_sc%vRMl<7N$`BC$zs3f!~B8HAX=@`sHIq(karxM?4siodYa7fb;tJfT919Df-19eMlD3b^&vM8a)Kia0hOmwb= z9=QgLDCIw5YwoSI{?7 ze&o_#91?|5X1i@V`{W2m&*hF_LAR=u1>T@wRzE$q+i_5LQ_mzLv15G9Vw`i1wXMTn zL@!d$eio7F_z;`Fg?>0awr}?J+y^|bRm(&1rSRK4Y`jlUJGsm`mrl*6puJz!>wp0E z1&NstSQw|6xfi06m1cjSzI>fcSk@0Vm~7-Pal6k!S&kww$szsS|8fG|f^Yr`*PTUk zVD5a{m$$+WEKj_;U}iq9p)=p_!>^ zUQ>ION3A?W6@Kk-l>au}@g}PwA+2yayYD^^#^EhH#a+?sjS=w!6<=PpY1-m1hnyK7 z?tQs%imb%LDrlv7&?+!&-AD+epYgPz>s}G)JS(fFy!z zaq!&3_ujSdA8Yg!^-pD@Lc5h2h?IdX$>ARNr3W^ZR%voGI@)8c6q^Cis1em1Rag>@ z+q%i|QgwN_d-`3-52@>oNIF7#EV(zOY;$S0MQZjn90wcjdmD^b*P`hH)qiqMFaA}h zx;?fa#VUE=_>uVnB0JL$TsZWe75U>AlwgZL6=PYBY~%!qcNy2LlBBRu8Zx+as?ORtFLx%=Yl zrISf%!Wj~>pc_ByUWPatdRd63-vxgF0eG|4bMGWIkUWs&T{kEKqt>aJI;V_G1g&Wpm(C4WG=D(7#;kRE~Q0yJQ<3z04g6+eH zZF_*ls(-aMiuMXJg-6>2Xtto1kg&rZAc?0+{_nB*t zhU&lTq5e3kcJhKpec4bbRb^Wuz)&oGyICY`lE?A%`Sh7?dzWC4;A6X6a>}0AID7Ub zF^()p4xWEM)Ru%w7S*Uju6`7?jS9t$39~nBcB9Hy$Y?i=%9r&yx?BASj_JllZ{kQg zPh>k0MXi(9z9J2 z(+?E%SlVpm)m4Hj>v!y&g5G*`)Ea-2zyDTgv#=TF%L^VJ3kUP0FGgNGr#p5&elP)o zrs!o+QL1xTvsG|bjyt}@mwFKY%6RnO_N=l! zgd~atr>EM+?(cP?$VYO$0ViTZwWeiS-{7ALR0Q5W=Lwy{eD$%3k%GOG;C%+~H4e7i znM&1a44@D%N@AH|mk(vlXn&Q0x#F)Eu0rq2BCw(NlsIMSxo{i?H1sK!hemrY^U)0t zqXLcSDJ*C}a%Y4#mMYAI0|_v@=G<=rmc`9)W?r1=JzGqudOAj+m^ZRaY8KgutG{|3 z(6uF=EMh)_y-LO2B^lt!rF$Ni6f?%Z;Y8ll8A+W4Ef>?Lz5>fm@!} z)g<-rZLg+41QiM2Iy}r2idOom6cKhG-~BcFqKykjPvk~Zp}+mYbohHSMXoe6IAXRn z&a`mf-+eC{5BE|X4%WK$`?1lHN%+Qkv*WNj`TpHEqHClY)SahRCZ8)Qq2-}Yc?3Xp z(||xdlUiRc+HgiB8+syYvzgu?gR44#bA^H0!$xrw=OsaN+4%%7&Olmz$9aP-op}q{@-eweoM8$%g-XB;ILotd< z&li6Buu@`tC7~f_S-YukY*qznpGc}~JX1NJ8NP7jj{aRD4A~d|jIFfG5VQIdE z3}^qx;{CQh9vTuw#li%@y7yTWV1*#A;dk^!-tTF#{{`Dad>IQzE`{6fKyH8UaBZ%s z`uL1c5?vJY3@=PPh=BK?pmfnL4(A-~YO;1MbMTf{dxugU@<2nzXYH(OrZifXk|U@> zr&6gbwDqJsh`nRUne*$4n*PdhfHV_$mJSc=T)$W?$zN+5x((0WIvboPpGOJU*X~)F5ed&y`ZvO1F<%n zkhSA-CE5OiE526w?Ei#n$tA5PJ2Noa2iFB;l{%d=I@UbO71Wm;D@CzcQlm~m75jnD zA+AN~Z6CN?Rnx9#!|JcuELqf!oZkxmKl!o6_$*g8liCw1Ci@{aiu$Dn9=W9Q03&?J z^D(3(q|ip)(@SEqevM=M1B^ESa^l911PS_4KS&KZWv1L1eK$8!E}o$R$~|e$9`-H( z{WFw^X{|>D^V0~p36UeZ>idylbbh=ynu9`5Q3N=$zrVqel7$qgzdjF-=J5liB*tj6 z(?JCkdP4X-eN%FUIu$G5Gr!Ld+tWbA3zH9~QP96)K(x7-3T@N6_i&B6T~2vBk=N#$ z_hV3Opreog&6xo-IpZsHBsPdusRVHTKEl(y|Bt}I(!;iUr^7ZHywVJ;5990L{Ggb| d`TOaP-Wms4yCt~kZE + + + Compare Config Assessment Tool Results + + + +
+

Compare Config Assessment Tool Results

+ + + + {% if message %} +

{{ message | safe }}

+ {% else %} +
+ +
+ +

+ +
+ +

+ +
+ {% endif %} +
+ + diff --git a/compare-plugin/test.py b/compare-plugin/test.py new file mode 100644 index 0000000..f1499aa --- /dev/null +++ b/compare-plugin/test.py @@ -0,0 +1,1751 @@ +import os +import json +import sys +import logging +import webbrowser +from flask import Flask, request, send_file, render_template +import openpyxl +from openpyxl.styles import PatternFill, Font +from openpyxl.utils.dataframe import dataframe_to_rows +from openpyxl import load_workbook +import pandas as pd +from copy import copy +from pptx import Presentation +from pptx.util import Inches, Pt +from pptx.enum.text import PP_ALIGN +from pptx.dml.color import RGBColor +import xlwings as xw + +app = Flask(__name__) + +# Load configuration from JSON file +def load_config(): + # Determine the current script directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct the full path to the config.json file in the compare_results directory + config_path = os.path.join(script_dir, 'config.json') # Adjusted to directly access config.json + + if not os.path.exists(config_path): + raise FileNotFoundError(f"Config file not found: {config_path}") + + with open(config_path) as f: + config = json.load(f) + + # Convert relative paths to absolute paths + config['upload_folder'] = os.path.join(script_dir, config.get('upload_folder', 'uploads')) + config['result_folder'] = os.path.join(script_dir, config.get('result_folder', 'results')) + + return config + +# Load the configuration +config = load_config() + +# Configure upload and result folders from config +UPLOAD_FOLDER = config['upload_folder'] +RESULT_FOLDER = config['result_folder'] + +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['RESULT_FOLDER'] = RESULT_FOLDER +logging.basicConfig(level=logging.DEBUG) + +# Ensure folders exist +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) +os.makedirs(app.config['RESULT_FOLDER'], exist_ok=True) + +# Add the controller check after the files are loaded and before processing +def check_controllers_match(previous_file_path, current_file_path): + # Load the previous and current workbooks + previous_workbook = pd.read_excel(previous_file_path, sheet_name='Analysis') + current_workbook = pd.read_excel(current_file_path, sheet_name='Analysis') + + # Extract the 'controller' column from both workbooks + previous_controllers = previous_workbook['controller'].unique() + current_controllers = current_workbook['controller'].unique() + + # Check if the controllers match + if not (len(previous_controllers) == 1 and len(current_controllers) == 1 and previous_controllers[0] == current_controllers[0]): + print(f"Error: The controllers in the provided workbooks do not match.\n" + f"Previous workbook controller: {previous_controllers[0]}\n" + f"Current workbook controller: {current_controllers[0]}") + sys.exit(1) # Exit the script + +# Function to generate PowerPoint slide +def generate_powerpoint_from_analysis(comparison_result_path, powerpoint_output_path): + logging.debug("Generating PowerPoint presentation...") + + try: + # Load the Analysis sheet from the Excel file + df = pd.read_excel(comparison_result_path, sheet_name='Analysis') + logging.debug("Loaded Analysis sheet successfully.") + logging.debug(f"DataFrame head:\n{df.head()}") # Print the first few rows for inspection + + # Initialize counts + results = {} + columns = [ + 'AppAgentsAPM', 'MachineAgentsAPM', 'BusinessTransactionsAPM', + 'BackendsAPM', 'OverheadAPM', 'ServiceEndpointsAPM', + 'ErrorConfigurationAPM', 'HealthRulesAndAlertingAPM', + 'DataCollectorsAPM', 'DashboardsAPM', 'OverallAssessment' + ] + + total_applications = len(df) # Total number of applications + + for col in columns: + # Extract upgrade and downgrade information + df[col] = df[col].astype(str) # Ensure all data is treated as strings + + upgraded_count = df[col].str.contains('upgraded', case=False, na=False).sum() + downgraded_count = df[col].str.contains('downgraded', case=False, na=False).sum() + + # Store results + results[col] = { + 'upgraded': upgraded_count, + 'downgraded': downgraded_count + } + logging.debug(f"Column: {col}, Upgraded: {upgraded_count}, Downgraded: {downgraded_count}") + + # Create a PowerPoint presentation + prs = Presentation() + slide_layout = prs.slide_layouts[5] # Title and Content layout + + slide = prs.slides.add_slide(slide_layout) + shapes = slide.shapes + + # Add title and subheading + title_shape = shapes.title + title_shape.text = "Assessment Comparison - Status" + + # Add a subheading for the total number of applications + textbox = shapes.add_textbox(Inches(0.5), Inches(1.0), Inches(8), Inches(0.5)) + text_frame = textbox.text_frame + p = text_frame.add_paragraph() + p.text = f"Total number of Applications Compared: {total_applications}" + p.font.size = Pt(14) # Set the font size for the subheading + + # Center align the text in the textbox + text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER + textbox.left = Inches(0.5) # Center the textbox horizontally + textbox.width = Inches(8) # Ensure it spans across the slide width + + # Add table to the slide + rows = len(columns) + 1 + cols = 3 # Total, Upgraded, Downgraded columns + table = shapes.add_table(rows, cols, Inches(0.5), Inches(2.0), Inches(8), Inches(4)).table + + # Set table headers + table.cell(0, 0).text = 'Metric' + table.cell(0, 1).text = 'Maturity Increase' + table.cell(0, 2).text = 'Maturity Decrease' + + # Set font size for headers + for cell in table.rows[0].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Populate the table + for i, col in enumerate(columns, start=1): + table.cell(i, 0).text = col + table.cell(i, 1).text = f"{results[col]['upgraded'] / total_applications * 100:.2f}%" + table.cell(i, 2).text = f"{results[col]['downgraded'] / total_applications * 100:.2f}%" + + # Set font size for data cells + for cell in table.rows[i].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Save the presentation + prs.save(powerpoint_output_path) + logging.debug(f"PowerPoint saved to {powerpoint_output_path}.") + + except Exception as e: + logging.error(f"Error generating PowerPoint: {e}", exc_info=True) + raise + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/upload', methods=['POST']) +def upload(): + logging.debug("Request files: %s", request.files) + + if 'previous_file' not in request.files or 'current_file' not in request.files: + logging.error("No file part") + return render_template('index.html', message="Error: No file part was uploaded."), 400 + + previous_file = request.files.get('previous_file') + current_file = request.files.get('current_file') + + if not previous_file or previous_file.filename == '': + logging.error("No selected file for previous") + return render_template('index.html', message="Error: No previous file was selected."), 400 + + if not current_file or current_file.filename == '': + logging.error("No selected file for current") + return render_template('index.html', message="Error: No current file was selected."), 400 + + previous_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous.xlsx') + current_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current.xlsx') + output_file_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_result.xlsx') + previous_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous_sum.xlsx') + current_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current_sum.xlsx') + comparison_sum_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_sum.xlsx') + powerpoint_output_path = os.path.join(app.config['RESULT_FOLDER'], 'Analysis_Summary.pptx') + + try: + # Save the uploaded files + previous_file.save(previous_file_path) + current_file.save(current_file_path) + + # Load previous and current workbooks + previous_workbook = pd.read_excel(previous_file_path, sheet_name='Analysis') + current_workbook = pd.read_excel(current_file_path, sheet_name='Analysis') + + # Check if controllers are the same + previous_controller = previous_workbook['controller'].unique() + current_controller = current_workbook['controller'].unique() + + if len(previous_controller) != 1 or len(current_controller) != 1 or previous_controller[0] != current_controller[0]: + logging.error("Controllers do not match.") + return render_template('index.html', message="Error: The controllers in the two files do not match. Please upload files from the same controller."), 400 + + # Create previous_sum and current_sum workbooks for Summary sheet + create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path) + + # Perform the comparison only for Summary using previous_sum and current_sum + compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path) + + # Perform comparison for other sheets + compare_files_other_sheets(previous_file_path, current_file_path, output_file_path) + + # Copy the Summary sheet from comparison_sum to comparison_result + copy_summary_to_result(comparison_sum_path, output_file_path) + + # Generate PowerPoint presentation from the Analysis sheet + logging.debug("Generating PowerPoint presentation...") + generate_powerpoint_from_analysis(output_file_path, powerpoint_output_path) + + # After successful processing, return a success message with a link to the result file + return render_template( + 'index.html', + message=( + f"Comparison completed successfully. " + f"You can download the results from your browser by clicking " + f"here " + f"and the PowerPoint summary by clicking " + f"here.
" + f"
Click here to return to the home page" + ) + ) + + except Exception as e: + logging.error(f"Error during file upload or comparison: {e}", exc_info=True) + return render_template('index.html', message="Error during file upload or comparison"), 500 + + +@app.route('/download/') +def download_file(filename): + # Provide a download link for the output file + return send_file(os.path.join(app.config['RESULT_FOLDER'], filename), as_attachment=True) + + +# Define color fills for Excel cells +red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid') +green_fill = PatternFill(start_color='00FF00', end_color='00FF00', fill_type='solid') +added_fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') + +# Helper function to find column index by name +def get_key_column(sheet, key_name): + for i, cell in enumerate(sheet[1], 1): + if cell.value == key_name: + return i + return None + +# Function to create summary workbooks +def create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path): + try: + wb_previous = load_workbook(previous_file_path, data_only=True) + wb_current = load_workbook(current_file_path, data_only=True) + + if 'Summary' not in wb_previous.sheetnames or 'Summary' not in wb_current.sheetnames: + logging.error("'Summary' sheet is missing in one of the files.") + return + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + + # Create new workbooks for the summaries + wb_previous_sum = openpyxl.Workbook() + wb_current_sum = openpyxl.Workbook() + + ws_previous_sum = wb_previous_sum.active + ws_current_sum = wb_current_sum.active + + ws_previous_sum.title = 'Summary' + ws_current_sum.title = 'Summary' + + # Copy data from original workbooks to summary workbooks as values only + for row in ws_previous.iter_rows(values_only=True): + ws_previous_sum.append(row) + for row in ws_current.iter_rows(values_only=True): + ws_current_sum.append(row) + + # Save the cleaned-up summary workbooks + wb_previous_sum.save(previous_sum_path) + wb_current_sum.save(current_sum_path) + + except Exception as e: + logging.error(f"Error in create_summary_workbooks: {e}", exc_info=True) + raise + + +# Function to compare 'Summary' sheet and save to a new workbook +def compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path): + try: + # Load the previous_sum and current_sum Excel files + wb_previous = load_workbook(previous_sum_path, data_only=True) + wb_current = load_workbook(current_sum_path, data_only=True) + wb_output = openpyxl.Workbook() + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + ws_output = wb_output.active + ws_output.title = 'Summary' + + # Debugging: Print sheet names and some data from the 'Summary' sheet + print("Previous Workbook Sheets:", wb_previous.sheetnames) + print("Current Workbook Sheets:", wb_current.sheetnames) + print("Example data from 'Summary' sheet in Previous Workbook (1,1):", ws_previous.cell(row=1, column=1).value) + print("Example data from 'Summary' sheet in Current Workbook (1,1):", ws_current.cell(row=1, column=1).value) + + logging.debug(f"Processing sheet: 'Summary'") + + compare_summary(ws_previous, ws_current, ws_output) + + # Save the workbook after all modifications have been completed + wb_output.save(comparison_sum_path) + logging.debug(f"Summary comparison saved to: {comparison_sum_path}") + + except Exception as e: + logging.error(f"Error in compare_files_summary: {e}", exc_info=True) + raise + + +# Function to compare summaries of both sheets +def compare_summary(ws_previous, ws_current, ws_output): + from openpyxl.styles import PatternFill + + # Define fill styles + red_fill = PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid") + green_fill = PatternFill(start_color="00FF00", end_color="00FF00", fill_type="solid") + + for row in ws_previous.iter_rows(min_row=1, min_col=1, max_col=ws_previous.max_column, max_row=ws_previous.max_row): + for cell in row: + prev_cell = ws_previous.cell(row=cell.row, column=cell.column) + curr_cell = ws_current.cell(row=cell.row, column=cell.column) + output_cell = ws_output.cell(row=cell.row, column=cell.column) + + prev_value = prev_cell.value + curr_value = curr_cell.value + + if prev_value is None: + prev_value = '' + if curr_value is None: + curr_value = '' + + logging.debug(f"Comparing cell ({cell.row},{cell.column}): Previous Value: {prev_value}, Current Value: {curr_value}") + + if prev_value != curr_value: + if isinstance(prev_value, (int, float)) and isinstance(curr_value, (int, float)): + if curr_value > prev_value: + output_cell.fill = green_fill + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.value = prev_value + + logging.debug(f"Cell ({cell.row},{cell.column}) updated to: {output_cell.value}") + + +def eval_formula(ws, cell): + """ Helper function to evaluate a cell's formula and return the result. """ + try: + if cell.data_type == 'f': + # Create a temporary workbook to evaluate the formula + temp_wb = openpyxl.Workbook() + temp_ws = temp_wb.active + temp_ws.cell(row=1, column=1).value = cell.value + + # Copy relevant data from the original sheet + for row in range(1, ws.max_row + 1): + for col in range(1, ws.max_column + 1): + temp_ws.cell(row=row + 1, column=col).value = ws.cell(row=row, column=col).value + + # Save and reopen to evaluate formulas + temp_file = "temp.xlsx" + temp_wb.save(temp_file) + temp_wb.close() + + temp_wb = openpyxl.load_workbook(temp_file) + temp_ws = temp_wb.active + eval_result = temp_ws['A1'].value + temp_wb.close() + + return eval_result + except Exception as e: + logging.error(f"Error evaluating formula in cell {cell.coordinate}: {e}", exc_info=True) + return None + +# Function to copy the Summary sheet from comparison_sum to comparison_result +def copy_summary_to_result(comparison_sum_path, output_file_path): + try: + # Load the comparison_sum and output workbooks + wb_comparison_sum = load_workbook(comparison_sum_path) + wb_output = load_workbook(output_file_path) + + # Get the Summary sheet from comparison_sum + ws_comparison_sum = wb_comparison_sum['Summary'] + + # If the Summary sheet already exists in output, delete it + if 'Summary' in wb_output.sheetnames: + del wb_output['Summary'] + + # Create a new Summary sheet in the output workbook + ws_output = wb_output.create_sheet('Summary', 0) # Insert Summary as the first sheet + + # Copy data and formatting from the comparison_sum Summary sheet to the output Summary sheet + for row in ws_comparison_sum.iter_rows(): + for cell in row: + new_cell = ws_output.cell(row=cell.row, column=cell.column, value=cell.value) + + # Copy individual style attributes + if cell.has_style: + new_cell.font = copy(cell.font) + new_cell.border = copy(cell.border) + new_cell.fill = copy(cell.fill) + new_cell.number_format = cell.number_format + new_cell.protection = copy(cell.protection) + new_cell.alignment = copy(cell.alignment) + + # Define header colors for Bronze, Silver, Gold, and Platinum + header_colors = { + 'B1': 'cd7f32', # Bronze + 'C1': 'c0c0c0', # Silver + 'D1': 'ffd700', # Gold + 'E1': 'e5e4e2' # Platinum + } + + # Apply colors to the headers in the first row + for col in header_colors: + cell = ws_output[col] + cell.fill = PatternFill(start_color=header_colors[col], end_color=header_colors[col], fill_type="solid") + cell.font = Font(bold=True, color="000000") + + # Save the output workbook + wb_output.save(output_file_path) + logging.debug("Summary sheet copied to the final comparison result and placed as the first sheet with highlighted headers.") + + except Exception as e: + logging.error(f"Error in copy_summary_to_result: {e}", exc_info=True) + raise + +# Function to compare files for all other sheets +def compare_files_other_sheets(previous_file_path, current_file_path, output_file_path): + try: + wb_previous = load_workbook(previous_file_path) + wb_current = load_workbook(current_file_path) + + for sheet_name in wb_current.sheetnames: + if sheet_name in wb_previous.sheetnames: + ws_previous = wb_previous[sheet_name] + ws_current = wb_current[sheet_name] + + logging.debug(f"Processing sheet: {sheet_name}") + + if sheet_name == 'Analysis': + compare_analysis(ws_previous, ws_current) + elif sheet_name == 'AppAgentsAPM': + compare_appagentsapm(ws_previous, ws_current) + elif sheet_name == 'MachineAgentsAPM': + compare_machineagentsapm(ws_previous, ws_current) + elif sheet_name == 'BusinessTransactionsAPM': + compare_businesstransactionsapm(ws_previous, ws_current) + elif sheet_name == 'BackendsAPM': + compare_backendsapm(ws_previous, ws_current) + elif sheet_name == 'OverheadAPM': + compare_overheadapm(ws_previous, ws_current) + elif sheet_name == 'ServiceEndpointsAPM': + compare_serviceendpointsapm(ws_previous, ws_current) + elif sheet_name == 'ErrorConfigurationAPM': + compare_errorconfigurationapm(ws_previous, ws_current) + elif sheet_name == 'HealthRulesAndAlertingAPM': + compare_healthrulesandalertingapm(ws_previous, ws_current) + elif sheet_name == 'DataCollectorsAPM': + compare_datacollectorsapm(ws_previous, ws_current) + elif sheet_name == 'DashboardsAPM': + compare_dashboardsapm(ws_previous, ws_current) + elif sheet_name == 'OverallAssessmentAPM': + compare_overallassessmentapm(ws_previous, ws_current) + elif sheet_name == 'Summary': + continue + else: + logging.warning(f"No comparison function defined for sheet: {sheet_name}") + + wb_current.save(output_file_path) + logging.debug(f"Comparison results saved to: {output_file_path}") + + except Exception as e: + logging.error(f"Error in compare_files_other_sheets: {e}", exc_info=True) + raise + +def compare_appagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'metricLimitNotHit': None, + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + if column == 'metricLimitNotHit': + # Handle boolean logic for metricLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_appagentsapm: {e}", exc_info=True) + raise + +def compare_machineagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None, + 'percentAgentsInstalledAlongsideAppAgents': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle numeric logic for percentage columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_machineagentsapm: {e}", exc_info=True) + raise + +def compare_datacollectorsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfDataCollectorFieldsConfigured': None, + 'numberOfDataCollectorFieldsCollectedInSnapshots': None, + 'numberOfDataCollectorFieldsCollectedInAnalytics': None, + 'biqEnabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'biqEnabled': + # Handle boolean logic for biqEnabled + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_datacollectorsapm: {e}", exc_info=True) + raise + +def compare_backendsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentBackendsWithLoad': None, + 'backendLimitNotHit': None, + 'numberOfCustomBackendRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'backendLimitNotHit': + # Handle boolean logic for backendLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Increased)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Decreased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_backendsapm: {e}", exc_info=True) + raise + +def compare_overheadapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'developerModeNotEnabledForAnyBT': None, + 'findEntryPointsNotEnabled': None, + 'aggressiveSnapshottingNotEnabled': None, + 'developerModeNotEnabledForApplication': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle boolean logic for specified columns + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overheadapm: {e}", exc_info=True) + raise + +def compare_healthrulesandalertingapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfHealthRuleViolations': None, + 'numberOfDefaultHealthRulesModified': None, + 'numberOfActionsBoundToEnabledPolicies': None, + 'numberOfCustomHealthRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'numberOfHealthRuleViolations': + if curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + else: + # For other columns + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_healthrulesandalertingapm: {e}", exc_info=True) + raise + +def compare_errorconfigurationapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'successPercentageOfWorstTransaction': None, + 'numberOfCustomRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'successPercentageOfWorstTransaction': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + elif column == 'numberOfCustomRules': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_errorconfigurationapm: {e}", exc_info=True) + raise + +def compare_serviceendpointsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfCustomServiceEndpointRules': None, + 'serviceEndpointLimitNotHit': None, + 'percentServiceEndpointsWithLoadOrDisabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfCustomServiceEndpointRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'serviceEndpointLimitNotHit': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'percentServiceEndpointsWithLoadOrDisabled': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_serviceendpointsapm: {e}", exc_info=True) + raise + +def compare_dashboardsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfDashboards': None, + 'percentageOfDashboardsModifiedLast6Months': None, + 'numberOfDashboardsUsingBiQ': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_dashboardsapm: {e}", exc_info=True) + raise + +def compare_overallassessmentapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'percentageTotalPlatinum': None, + 'percentageTotalGoldOrBetter': None, + 'percentageTotalSilverOrBetter': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overallassessmentapm: {e}", exc_info=True) + raise + +# Function to compare 'Business Transactions' sheet +def compare_businesstransactionsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfBTs': None, + 'percentBTsWithLoad': None, + 'btLockdownEnabled': None, + 'numberCustomMatchRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfBTs': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if 201 <= prev_value_num <= 600: + if curr_value_num < prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + elif curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + + elif column == 'percentBTsWithLoad': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'btLockdownEnabled': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'numberCustomMatchRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_businesstransactionsapm: {e}", exc_info=True) + raise + +def compare_analysis(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'AppAgentsAPM': None, + 'MachineAgentsAPM': None, + 'BusinessTransactionsAPM': None, + 'BackendsAPM': None, + 'OverheadAPM': None, + 'ServiceEndpointsAPM': None, + 'ErrorConfigurationAPM': None, + 'HealthRulesAndAlertingAPM': None, + 'DataCollectorsAPM': None, + 'DashboardsAPM': None, + 'OverallAssessment': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + name_col_prev = get_key_column(ws_previous, 'name') + name_col_curr = get_key_column(ws_current, 'name') + + if name_col_prev is None or name_col_curr is None: + logging.error("The 'name' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Comparison logic based on ranking + ranking = {'bronze': 1, 'silver': 2, 'gold': 3, 'platinum': 4} + prev_rank = ranking.get(previous_value.lower(), 0) + curr_rank = ranking.get(current_value.lower(), 0) + + if curr_rank > prev_rank: + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Upgraded)" + elif curr_rank < prev_rank: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Downgraded)" + except ValueError: + logging.error(f"Invalid ranking value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_analysis: {e}", exc_info=True) + raise + +if __name__ == '__main__': + # Automatically open the default web browser to the correct URL + url = "http://127.0.0.1:5000" # This is the default URL where Flask serves + webbrowser.open(url) + + # Run the Flask app + app.run(debug=True) diff --git a/compare-plugin/test1.py b/compare-plugin/test1.py new file mode 100644 index 0000000..9f588b2 --- /dev/null +++ b/compare-plugin/test1.py @@ -0,0 +1,1786 @@ +import os +import json +import sys +import logging +import webbrowser +from flask import Flask, request, send_file, render_template +import openpyxl +from openpyxl.styles import PatternFill, Font +from openpyxl.utils.dataframe import dataframe_to_rows +from openpyxl import load_workbook +import pandas as pd +from copy import copy +from pptx import Presentation +from pptx.util import Inches, Pt +from pptx.enum.text import PP_ALIGN +from pptx.dml.color import RGBColor +import xlwings as xw + +app = Flask(__name__) + +def save_workbook(filepath): + """Open and save the workbook to ensure formulas are recalculated.""" + # Open the workbook + app = xw.App(visible=False) # Set visible=False to avoid showing the Excel window + wb = app.books.open(filepath) + + # Save the workbook + wb.save() + + # Close the workbook + wb.close() + + # Quit the application + app.quit() + +def process_files(previous_file_path, current_file_path): + # Save the workbooks to trigger formula recalculation + save_workbook(previous_file_path) + save_workbook(current_file_path) + + # Continue with your comparison logic + compare_files_summary(previous_file_path, current_file_path, 'comparison_summary.xlsx') + +# Load configuration from JSON file +def load_config(): + # Determine the current script directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct the full path to the config.json file + config_path = os.path.join(script_dir, 'config.json') + + if not os.path.exists(config_path): + raise FileNotFoundError(f"Config file not found: {config_path}") + + with open(config_path) as f: + config = json.load(f) + + # Convert relative paths to absolute paths + config['upload_folder'] = os.path.join(script_dir, config.get('upload_folder', 'uploads')) + config['result_folder'] = os.path.join(script_dir, config.get('result_folder', 'results')) + + return config + +# Load the configuration +config = load_config() + +# Configure upload and result folders from config +UPLOAD_FOLDER = config['upload_folder'] +RESULT_FOLDER = config['result_folder'] + +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['RESULT_FOLDER'] = RESULT_FOLDER +logging.basicConfig(level=logging.DEBUG) + +# Ensure folders exist +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) +os.makedirs(app.config['RESULT_FOLDER'], exist_ok=True) + +def check_controllers_match(previous_file_path, current_file_path): + # Load the previous and current workbooks + previous_workbook = pd.read_excel(previous_file_path, sheet_name='Analysis') + current_workbook = pd.read_excel(current_file_path, sheet_name='Analysis') + + # Extract the 'controller' column from both workbooks and strip whitespaces + previous_controllers = previous_workbook['controller'].dropna().str.strip().unique() + current_controllers = current_workbook['controller'].dropna().str.strip().unique() + + # Log the exact controller values for debugging + logging.debug(f"Previous controller(s): {previous_controllers}") + logging.debug(f"Current controller(s): {current_controllers}") + + # Check if the controllers match + if not (len(previous_controllers) == 1 and len(current_controllers) == 1 and previous_controllers[0] == current_controllers[0]): + logging.error(f"Controllers do not match. Previous controller: {previous_controllers}, Current controller: {current_controllers}") + return False + + return True + +def generate_powerpoint_from_analysis(comparison_result_path, powerpoint_output_path): + logging.debug("Generating PowerPoint presentation...") + + try: + # Create a PowerPoint presentation + prs = Presentation() + slide_layout_title = prs.slide_layouts[0] # Title slide layout + slide_layout_content = prs.slide_layouts[5] # Title and Content layout + + # Slide 1: Title slide with "CAT Compare" + slide = prs.slides.add_slide(slide_layout_title) + title_shape = slide.shapes.title + title_shape.text = "CAT Compare" + + # Slide 2: Content from 'Summary' tab in table format + summary_df = pd.read_excel(comparison_result_path, sheet_name='Summary') + logging.debug("Loaded Summary sheet successfully.") + logging.debug(f"Summary DataFrame head:\n{summary_df.head()}") + + # Add a new slide for the Summary content + slide = prs.slides.add_slide(slide_layout_content) + title_shape = slide.shapes.title + title_shape.text = "Summary Tab" + + # Add a table for the summary data + rows, cols = summary_df.shape + table = slide.shapes.add_table(rows + 1, cols, Inches(0.5), Inches(1.5), Inches(8), Inches(5)).table + + # Set the column headers (from DataFrame columns) + for col_idx, column in enumerate(summary_df.columns): + table.cell(0, col_idx).text = str(column) + table.cell(0, col_idx).text_frame.paragraphs[0].font.size = Pt(12) + + # Add the data rows + for row_idx, row in summary_df.iterrows(): + for col_idx, value in enumerate(row): + table.cell(row_idx + 1, col_idx).text = str(value) + table.cell(row_idx + 1, col_idx).text_frame.paragraphs[0].font.size = Pt(12) + + # Slide 3: The current slide with Assessment comparison + df = pd.read_excel(comparison_result_path, sheet_name='Analysis') + logging.debug("Loaded Analysis sheet successfully.") + logging.debug(f"DataFrame head:\n{df.head()}") + + # Initialize counts + results = {} + columns = [ + 'AppAgentsAPM', 'MachineAgentsAPM', 'BusinessTransactionsAPM', + 'BackendsAPM', 'OverheadAPM', 'ServiceEndpointsAPM', + 'ErrorConfigurationAPM', 'HealthRulesAndAlertingAPM', + 'DataCollectorsAPM', 'DashboardsAPM', 'OverallAssessment' + ] + + total_applications = len(df) # Total number of applications + + for col in columns: + # Extract upgrade and downgrade information + df[col] = df[col].astype(str) + upgraded_count = df[col].str.contains('upgraded', case=False, na=False).sum() + downgraded_count = df[col].str.contains('downgraded', case=False, na=False).sum() + + # Store results + results[col] = { + 'upgraded': upgraded_count, + 'downgraded': downgraded_count + } + logging.debug(f"Column: {col}, Upgraded: {upgraded_count}, Downgraded: {downgraded_count}") + + # Add the third slide for Assessment Comparison + slide = prs.slides.add_slide(slide_layout_content) + title_shape = slide.shapes.title + title_shape.text = "Assessment Comparison - Status" + + textbox = slide.shapes.add_textbox(Inches(0.5), Inches(1.0), Inches(8), Inches(0.5)) + text_frame = textbox.text_frame + p = text_frame.add_paragraph() + p.text = f"Total number of Applications Compared: {total_applications}" + p.font.size = Pt(14) + text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER + textbox.left = Inches(0.5) + textbox.width = Inches(8) + + # Add table to the slide + rows = len(columns) + 1 + cols = 3 # Total, Upgraded, Downgraded columns + table = slide.shapes.add_table(rows, cols, Inches(0.5), Inches(2.0), Inches(8), Inches(4)).table + + # Set table headers + table.cell(0, 0).text = 'Metric' + table.cell(0, 1).text = 'Maturity Increase' + table.cell(0, 2).text = 'Maturity Decrease' + + # Set font size for headers + for cell in table.rows[0].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Populate the table + for i, col in enumerate(columns, start=1): + table.cell(i, 0).text = col + table.cell(i, 1).text = f"{results[col]['upgraded'] / total_applications * 100:.2f}%" + table.cell(i, 2).text = f"{results[col]['downgraded'] / total_applications * 100:.2f}%" + + for cell in table.rows[i].cells: + cell.text_frame.paragraphs[0].font.size = Pt(14) + + # Save the presentation + prs.save(powerpoint_output_path) + logging.debug(f"PowerPoint saved to {powerpoint_output_path}.") + + except Exception as e: + logging.error(f"Error generating PowerPoint: {e}", exc_info=True) + raise + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/upload', methods=['POST']) +def upload(): + logging.debug("Request files: %s", request.files) + + if 'previous_file' not in request.files or 'current_file' not in request.files: + logging.error("No file part") + return render_template('index.html', message="Error: No file part was uploaded."), 400 + + previous_file = request.files.get('previous_file') + current_file = request.files.get('current_file') + + if not previous_file or previous_file.filename == '': + logging.error("No selected file for previous") + return render_template('index.html', message="Error: No previous file was selected."), 400 + + if not current_file or current_file.filename == '': + logging.error("No selected file for current") + return render_template('index.html', message="Error: No current file was selected."), 400 + + previous_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous.xlsx') + current_file_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current.xlsx') + output_file_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_result.xlsx') + previous_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'previous_sum.xlsx') + current_sum_path = os.path.join(app.config['UPLOAD_FOLDER'], 'current_sum.xlsx') + comparison_sum_path = os.path.join(app.config['RESULT_FOLDER'], 'comparison_sum.xlsx') + powerpoint_output_path = os.path.join(app.config['RESULT_FOLDER'], 'Analysis_Summary.pptx') + + try: + # Save the uploaded files + previous_file.save(previous_file_path) + current_file.save(current_file_path) + + # Automatically save the workbooks to recalculate formulas + save_workbook(previous_file_path) + save_workbook(current_file_path) + + # Check if controllers match + if not check_controllers_match(previous_file_path, current_file_path): + logging.error("Controllers do not match.") + return render_template('index.html', message="Error: The controllers in the two files do not match. Please upload files from the same controller."), 400 + + # Proceed with comparison... + create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path) + compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path) + compare_files_other_sheets(previous_file_path, current_file_path, output_file_path) + copy_summary_to_result(comparison_sum_path, output_file_path) + generate_powerpoint_from_analysis(output_file_path, powerpoint_output_path) + + return render_template( + 'index.html', + message=( + f"Comparison completed successfully. " + f"You can download the results from your browser by clicking " + f"here " + f"and the PowerPoint summary by clicking " + f"here.
" + f"
Click here to return to the home page" + ) + ) + + except Exception as e: + logging.error(f"Error during file upload or comparison: {e}", exc_info=True) + return render_template('index.html', message="Error during file upload or comparison"), 500 + +@app.route('/download/') +def download_file(filename): + # Provide a download link for the output file + return send_file(os.path.join(app.config['RESULT_FOLDER'], filename), as_attachment=True) + + +# Define color fills for Excel cells +red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid') +green_fill = PatternFill(start_color='00FF00', end_color='00FF00', fill_type='solid') +added_fill = PatternFill(start_color='ADD8E6', end_color='ADD8E6', fill_type='solid') + +# Helper function to find column index by name +def get_key_column(sheet, key_name): + for i, cell in enumerate(sheet[1], 1): + if cell.value == key_name: + return i + return None + +# Function to create summary workbooks +def create_summary_workbooks(previous_file_path, current_file_path, previous_sum_path, current_sum_path): + try: + wb_previous = load_workbook(previous_file_path, data_only=True) + wb_current = load_workbook(current_file_path, data_only=True) + + if 'Summary' not in wb_previous.sheetnames or 'Summary' not in wb_current.sheetnames: + logging.error("'Summary' sheet is missing in one of the files.") + return + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + + # Create new workbooks for the summaries + wb_previous_sum = openpyxl.Workbook() + wb_current_sum = openpyxl.Workbook() + + ws_previous_sum = wb_previous_sum.active + ws_current_sum = wb_current_sum.active + + ws_previous_sum.title = 'Summary' + ws_current_sum.title = 'Summary' + + # Copy data from original workbooks to summary workbooks as values only + for row in ws_previous.iter_rows(values_only=True): + ws_previous_sum.append(row) + for row in ws_current.iter_rows(values_only=True): + ws_current_sum.append(row) + + # Save the cleaned-up summary workbooks + wb_previous_sum.save(previous_sum_path) + wb_current_sum.save(current_sum_path) + + except Exception as e: + logging.error(f"Error in create_summary_workbooks: {e}", exc_info=True) + raise + + +# Function to compare 'Summary' sheet and save to a new workbook +def compare_files_summary(previous_sum_path, current_sum_path, comparison_sum_path): + try: + # Load the previous_sum and current_sum Excel files + wb_previous = load_workbook(previous_sum_path, data_only=True) + wb_current = load_workbook(current_sum_path, data_only=True) + wb_output = openpyxl.Workbook() + + ws_previous = wb_previous['Summary'] + ws_current = wb_current['Summary'] + ws_output = wb_output.active + ws_output.title = 'Summary' + + # Debugging: Print sheet names and some data from the 'Summary' sheet + print("Previous Workbook Sheets:", wb_previous.sheetnames) + print("Current Workbook Sheets:", wb_current.sheetnames) + print("Example data from 'Summary' sheet in Previous Workbook (1,1):", ws_previous.cell(row=1, column=1).value) + print("Example data from 'Summary' sheet in Current Workbook (1,1):", ws_current.cell(row=1, column=1).value) + + logging.debug(f"Processing sheet: 'Summary'") + + compare_summary(ws_previous, ws_current, ws_output) + + # Save the workbook after all modifications have been completed + wb_output.save(comparison_sum_path) + logging.debug(f"Summary comparison saved to: {comparison_sum_path}") + + except Exception as e: + logging.error(f"Error in compare_files_summary: {e}", exc_info=True) + raise + + +# Function to compare summaries of both sheets +def compare_summary(ws_previous, ws_current, ws_output): + from openpyxl.styles import PatternFill + + # Define fill styles + red_fill = PatternFill(start_color="FF0000", end_color="FF0000", fill_type="solid") + green_fill = PatternFill(start_color="00FF00", end_color="00FF00", fill_type="solid") + + for row in ws_previous.iter_rows(min_row=1, min_col=1, max_col=ws_previous.max_column, max_row=ws_previous.max_row): + for cell in row: + prev_cell = ws_previous.cell(row=cell.row, column=cell.column) + curr_cell = ws_current.cell(row=cell.row, column=cell.column) + output_cell = ws_output.cell(row=cell.row, column=cell.column) + + prev_value = prev_cell.value + curr_value = curr_cell.value + + if prev_value is None: + prev_value = '' + if curr_value is None: + curr_value = '' + + logging.debug(f"Comparing cell ({cell.row},{cell.column}): Previous Value: {prev_value}, Current Value: {curr_value}") + + if prev_value != curr_value: + if isinstance(prev_value, (int, float)) and isinstance(curr_value, (int, float)): + if curr_value > prev_value: + output_cell.fill = green_fill + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.fill = red_fill + output_cell.value = f"{prev_value} → {curr_value}" + else: + output_cell.value = prev_value + + logging.debug(f"Cell ({cell.row},{cell.column}) updated to: {output_cell.value}") + + +def eval_formula(ws, cell): + """ Helper function to evaluate a cell's formula and return the result. """ + try: + if cell.data_type == 'f': + # Create a temporary workbook to evaluate the formula + temp_wb = openpyxl.Workbook() + temp_ws = temp_wb.active + temp_ws.cell(row=1, column=1).value = cell.value + + # Copy relevant data from the original sheet + for row in range(1, ws.max_row + 1): + for col in range(1, ws.max_column + 1): + temp_ws.cell(row=row + 1, column=col).value = ws.cell(row=row, column=col).value + + # Save and reopen to evaluate formulas + temp_file = "temp.xlsx" + temp_wb.save(temp_file) + temp_wb.close() + + temp_wb = openpyxl.load_workbook(temp_file) + temp_ws = temp_wb.active + eval_result = temp_ws['A1'].value + temp_wb.close() + + return eval_result + except Exception as e: + logging.error(f"Error evaluating formula in cell {cell.coordinate}: {e}", exc_info=True) + return None + +# Function to copy the Summary sheet from comparison_sum to comparison_result +def copy_summary_to_result(comparison_sum_path, output_file_path): + try: + # Load the comparison_sum and output workbooks + wb_comparison_sum = load_workbook(comparison_sum_path) + wb_output = load_workbook(output_file_path) + + # Get the Summary sheet from comparison_sum + ws_comparison_sum = wb_comparison_sum['Summary'] + + # If the Summary sheet already exists in output, delete it + if 'Summary' in wb_output.sheetnames: + del wb_output['Summary'] + + # Create a new Summary sheet in the output workbook + ws_output = wb_output.create_sheet('Summary', 0) # Insert Summary as the first sheet + + # Copy data and formatting from the comparison_sum Summary sheet to the output Summary sheet + for row in ws_comparison_sum.iter_rows(): + for cell in row: + new_cell = ws_output.cell(row=cell.row, column=cell.column, value=cell.value) + + # Copy individual style attributes + if cell.has_style: + new_cell.font = copy(cell.font) + new_cell.border = copy(cell.border) + new_cell.fill = copy(cell.fill) + new_cell.number_format = cell.number_format + new_cell.protection = copy(cell.protection) + new_cell.alignment = copy(cell.alignment) + + # Define header colors for Bronze, Silver, Gold, and Platinum + header_colors = { + 'B1': 'cd7f32', # Bronze + 'C1': 'c0c0c0', # Silver + 'D1': 'ffd700', # Gold + 'E1': 'e5e4e2' # Platinum + } + + # Apply colors to the headers in the first row + for col in header_colors: + cell = ws_output[col] + cell.fill = PatternFill(start_color=header_colors[col], end_color=header_colors[col], fill_type="solid") + cell.font = Font(bold=True, color="000000") + + # Save the output workbook + wb_output.save(output_file_path) + logging.debug("Summary sheet copied to the final comparison result and placed as the first sheet with highlighted headers.") + + except Exception as e: + logging.error(f"Error in copy_summary_to_result: {e}", exc_info=True) + raise + +# Function to compare files for all other sheets +def compare_files_other_sheets(previous_file_path, current_file_path, output_file_path): + try: + wb_previous = load_workbook(previous_file_path) + wb_current = load_workbook(current_file_path) + + for sheet_name in wb_current.sheetnames: + if sheet_name in wb_previous.sheetnames: + ws_previous = wb_previous[sheet_name] + ws_current = wb_current[sheet_name] + + logging.debug(f"Processing sheet: {sheet_name}") + + if sheet_name == 'Analysis': + compare_analysis(ws_previous, ws_current) + elif sheet_name == 'AppAgentsAPM': + compare_appagentsapm(ws_previous, ws_current) + elif sheet_name == 'MachineAgentsAPM': + compare_machineagentsapm(ws_previous, ws_current) + elif sheet_name == 'BusinessTransactionsAPM': + compare_businesstransactionsapm(ws_previous, ws_current) + elif sheet_name == 'BackendsAPM': + compare_backendsapm(ws_previous, ws_current) + elif sheet_name == 'OverheadAPM': + compare_overheadapm(ws_previous, ws_current) + elif sheet_name == 'ServiceEndpointsAPM': + compare_serviceendpointsapm(ws_previous, ws_current) + elif sheet_name == 'ErrorConfigurationAPM': + compare_errorconfigurationapm(ws_previous, ws_current) + elif sheet_name == 'HealthRulesAndAlertingAPM': + compare_healthrulesandalertingapm(ws_previous, ws_current) + elif sheet_name == 'DataCollectorsAPM': + compare_datacollectorsapm(ws_previous, ws_current) + elif sheet_name == 'DashboardsAPM': + compare_dashboardsapm(ws_previous, ws_current) + elif sheet_name == 'OverallAssessmentAPM': + compare_overallassessmentapm(ws_previous, ws_current) + elif sheet_name == 'Summary': + continue + else: + logging.warning(f"No comparison function defined for sheet: {sheet_name}") + + wb_current.save(output_file_path) + logging.debug(f"Comparison results saved to: {output_file_path}") + + except Exception as e: + logging.error(f"Error in compare_files_other_sheets: {e}", exc_info=True) + raise + +def compare_appagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'metricLimitNotHit': None, + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + if column == 'metricLimitNotHit': + # Handle boolean logic for metricLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_appagentsapm: {e}", exc_info=True) + raise + +def compare_machineagentsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentAgentsLessThan1YearOld': None, + 'percentAgentsLessThan2YearsOld': None, + 'percentAgentsReportingData': None, + 'percentAgentsRunningSameVersion': None, + 'percentAgentsInstalledAlongsideAppAgents': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle numeric logic for percentage columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_machineagentsapm: {e}", exc_info=True) + raise + +def compare_datacollectorsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfDataCollectorFieldsConfigured': None, + 'numberOfDataCollectorFieldsCollectedInSnapshots': None, + 'numberOfDataCollectorFieldsCollectedInAnalytics': None, + 'biqEnabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'biqEnabled': + # Handle boolean logic for biqEnabled + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Improved)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Declined)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_datacollectorsapm: {e}", exc_info=True) + raise + +def compare_backendsapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'percentBackendsWithLoad': None, + 'backendLimitNotHit': None, + 'numberOfCustomBackendRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value; retain original formatting or clear output + cell_output.value = previous_value # Ensure the value is set to the previous value + continue # Skip any further formatting or changes + + if column == 'backendLimitNotHit': + # Handle boolean logic for backendLimitNotHit + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Increased)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Decreased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + else: + # Handle numeric logic for other columns + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_backendsapm: {e}", exc_info=True) + raise + +def compare_overheadapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'developerModeNotEnabledForAnyBT': None, + 'findEntryPointsNotEnabled': None, + 'aggressiveSnapshottingNotEnabled': None, + 'developerModeNotEnabledForApplication': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + # Handle boolean logic for specified columns + if current_value == 'TRUE' and previous_value == 'FALSE': + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Improved)" + elif current_value == 'FALSE' and previous_value == 'TRUE': + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Declined)" + else: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Changed)" + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overheadapm: {e}", exc_info=True) + raise + +def compare_healthrulesandalertingapm(ws_previous, ws_current): + try: + # Define column names and their specific comparison logic + columns = { + 'numberOfHealthRuleViolations': None, + 'numberOfDefaultHealthRulesModified': None, + 'numberOfActionsBoundToEnabledPolicies': None, + 'numberOfCustomHealthRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'numberOfHealthRuleViolations': + if curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + else: + # For other columns + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_healthrulesandalertingapm: {e}", exc_info=True) + raise + +def compare_errorconfigurationapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'successPercentageOfWorstTransaction': None, + 'numberOfCustomRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + formatted_prev_value = f"{prev_value_num:.2f}" + formatted_curr_value = f"{curr_value_num:.2f}" + + if column == 'successPercentageOfWorstTransaction': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + elif column == 'numberOfCustomRules': + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Increased)" + else: + cell_output.fill = red_fill + cell_output.value = f"{formatted_prev_value} → {formatted_curr_value} (Decreased)" + except ValueError: + logging.error(f"Non-numeric value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_errorconfigurationapm: {e}", exc_info=True) + raise + +def compare_serviceendpointsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfCustomServiceEndpointRules': None, + 'serviceEndpointLimitNotHit': None, + 'percentServiceEndpointsWithLoadOrDisabled': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfCustomServiceEndpointRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'serviceEndpointLimitNotHit': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'percentServiceEndpointsWithLoadOrDisabled': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_serviceendpointsapm: {e}", exc_info=True) + raise + +def compare_dashboardsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfDashboards': None, + 'percentageOfDashboardsModifiedLast6Months': None, + 'numberOfDashboardsUsingBiQ': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_dashboardsapm: {e}", exc_info=True) + raise + +def compare_overallassessmentapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'percentageTotalPlatinum': None, + 'percentageTotalGoldOrBetter': None, + 'percentageTotalSilverOrBetter': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_overallassessmentapm: {e}", exc_info=True) + raise + +# Function to compare 'Business Transactions' sheet +def compare_businesstransactionsapm(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'numberOfBTs': None, + 'percentBTsWithLoad': None, + 'btLockdownEnabled': None, + 'numberCustomMatchRules': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + app_col_prev = get_key_column(ws_previous, 'application') + app_col_curr = get_key_column(ws_current, 'application') + + if app_col_prev is None or app_col_curr is None: + logging.error("The 'application' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + app_value = row[app_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (app_value, ctrl_value) + if app_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Handle each column's specific comparison logic + if column == 'numberOfBTs': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if 201 <= prev_value_num <= 600: + if curr_value_num < prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + elif curr_value_num > prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + + elif column == 'percentBTsWithLoad': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + + elif column == 'btLockdownEnabled': + if previous_value == "FALSE" and current_value == "TRUE": + cell_output.fill = green_fill + cell_output.value = "FALSE → TRUE" + elif previous_value == "TRUE" and current_value == "FALSE": + cell_output.fill = red_fill + cell_output.value = "TRUE → FALSE" + + elif column == 'numberCustomMatchRules': + prev_value_num = float(previous_value) + curr_value_num = float(current_value) + if curr_value_num > prev_value_num: + cell_output.fill = green_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Increased)" + elif curr_value_num < prev_value_num: + cell_output.fill = red_fill + cell_output.value = f"{prev_value_num:.2f} → {curr_value_num:.2f} (Decreased)" + except ValueError: + logging.error(f"Non-numeric or invalid value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_businesstransactionsapm: {e}", exc_info=True) + raise + +def compare_analysis(ws_previous, ws_current): + try: + # Define the columns for comparison + columns = { + 'AppAgentsAPM': None, + 'MachineAgentsAPM': None, + 'BusinessTransactionsAPM': None, + 'BackendsAPM': None, + 'OverheadAPM': None, + 'ServiceEndpointsAPM': None, + 'ErrorConfigurationAPM': None, + 'HealthRulesAndAlertingAPM': None, + 'DataCollectorsAPM': None, + 'DashboardsAPM': None, + 'OverallAssessment': None + } + + # Retrieve column indices + for column in columns.keys(): + col_idx_prev = get_key_column(ws_previous, column) + col_idx_curr = get_key_column(ws_current, column) + if col_idx_prev is None or col_idx_curr is None: + logging.error(f"The '{column}' column is missing in one of the sheets. Cannot proceed with comparison.") + return + columns[column] = (col_idx_prev, col_idx_curr) + + # Retrieve key column indices + ctrl_col_prev = get_key_column(ws_previous, 'controller') + ctrl_col_curr = get_key_column(ws_current, 'controller') + name_col_prev = get_key_column(ws_previous, 'name') + name_col_curr = get_key_column(ws_current, 'name') + + if name_col_prev is None or name_col_curr is None: + logging.error("The 'name' column is missing in one of the sheets. Cannot proceed with comparison.") + return + + if ctrl_col_prev is None or ctrl_col_curr is None: + logging.error("The 'controller' column is missing in one of the sheets. This might affect the comparison.") + return + + previous_data = {} + current_data = {} + + # Read previous data + for row in ws_previous.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_prev - 1].value + ctrl_value = row[ctrl_col_prev - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + previous_data[key] = row + + # Read current data + for row in ws_current.iter_rows(min_row=2, values_only=False): + name_value = row[name_col_curr - 1].value + ctrl_value = row[ctrl_col_curr - 1].value + key = (name_value, ctrl_value) + if name_value and ctrl_value: + current_data[key] = row + + # Compare previous data with current data + for key, previous_row in previous_data.items(): + current_row = current_data.get(key) + if current_row: + for column, (col_idx_prev, col_idx_curr) in columns.items(): + previous_value = previous_row[col_idx_prev - 1].value + current_value = current_row[col_idx_curr - 1].value + cell_output = ws_current.cell(row=current_row[0].row, column=col_idx_curr) + + # Log values being compared + # logging.debug(f"Comparing '{column}' for key '{key}': Previous={previous_value}, Current={current_value}") + + if previous_value == current_value: + # No change in value + continue + + try: + # Comparison logic based on ranking + ranking = {'bronze': 1, 'silver': 2, 'gold': 3, 'platinum': 4} + prev_rank = ranking.get(previous_value.lower(), 0) + curr_rank = ranking.get(current_value.lower(), 0) + + if curr_rank > prev_rank: + cell_output.fill = green_fill + cell_output.value = f"{previous_value} → {current_value} (Upgraded)" + elif curr_rank < prev_rank: + cell_output.fill = red_fill + cell_output.value = f"{previous_value} → {current_value} (Downgraded)" + except ValueError: + logging.error(f"Invalid ranking value encountered for column '{column}': Previous={previous_value}, Current={current_value}") + + # Add new entries in the current sheet + for key, current_row in current_data.items(): + if key not in previous_data: + row_index = ws_current.max_row + 1 + for col_num, cell in enumerate(current_row, 1): + new_cell = ws_current.cell(row=row_index, column=col_num, value=cell.value) + new_cell.fill = added_fill + + except Exception as e: + logging.error(f"Error in compare_analysis: {e}", exc_info=True) + raise + +if __name__ == '__main__': + # Automatically open the default web browser to the correct URL + url = "http://127.0.0.1:5000" # This is the default URL where Flask serves + webbrowser.open(url) + + # Run the Flask app + app.run(debug=True)