Files
android_development/tools/compare_cts_reports/generate_spread_sheet.py
Dennis Song 4b6317ed14 compare_cts_reports: do not show ignored ABI in the sheet
Do not show the ABI name in the compare result spread sheet
if `--ignore-abi` was specified when generating the csv
diff file.

Bug: 315073470
Test: compare_cts_reports.py and generate_spread_sheet.py
Change-Id: I3cd015dd24e6597a4f8453c73638f1302c8e6fb7
2023-12-11 11:04:58 +08:00

255 lines
7.9 KiB
Python

#!/usr/bin/python3
#
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
"""Convert the compare result csv file to a spreadsheet.
Prerequisite:
- Install the `gspread` python package.
- Create credentials to allow access to spreadsheets via Google Sheets API.
Usage example:
python3 generate_spread_sheet.py \
--compared_result compare_result/diff.csv \
--sheet_name "CTS Compare Result" \
--credentials_dir ~/.config/gspread/
"""
import argparse
import constant
import csv
import gspread
import os
from typing import List, Tuple
_COLOR_GREY = {'red': 0.37, 'green': 0.42, 'blue': 0.42}
_COLOR_WHITE = {'red': 0.95, 'green': 0.95, 'blue': 0.95}
_COLOR_YELLOW = {'red': 0.9, 'green': 0.8, 'blue': 0.07}
_COLOR_DARK_BLUE = {'red': 0.15, 'green': 0.15, 'blue': 0.46}
_SHEET_HEADER_FORMAT = {
'backgroundColor': _COLOR_GREY,
'horizontalAlignment': 'CENTER',
'textFormat': {
'foregroundColor': _COLOR_WHITE,
'fontSize': 11,
'bold': True,
},
}
_MODULE_HEADER_FORMAT = {
'backgroundColor': _COLOR_YELLOW,
'horizontalAlignment': 'LEFT',
'textFormat': {
'foregroundColor': _COLOR_DARK_BLUE,
'fontSize': 10,
'bold': True,
},
}
# The first four columns in compare_results are for test info.
_NUM_OF_INFO_COLUMNS = 4
def _parse_args() -> argparse.Namespace:
"""Parse the script arguments.
Returns:
An object of argparse.Namespace.
"""
parser = argparse.ArgumentParser()
parser.add_argument('--compared_result', required=True,
help='Path to the compared csv file.')
parser.add_argument('--sheet_name', required=True,
help='Name for the output spreadsheet.')
parser.add_argument('--credentials_dir', required=True,
help='Path to the directory that contains gspread '
'credentials files.')
return parser.parse_args()
def _read_csv(csv_path: str) -> Tuple[List[str], List[List[str]]]:
"""Read a csv comparison report and return as lists.
Args:
csv_path: The path to the csv comparison report.
Returns:
A List of report names, A List of parsed results.
"""
parsed_result = []
with open(csv_path, 'r') as csvfile:
result_reader = csv.reader(csvfile, delimiter=',')
header = next(result_reader)
report_names = header[_NUM_OF_INFO_COLUMNS:]
for row in result_reader:
parsed_result.append(row)
return report_names, parsed_result
def _create_spread_sheet(
new_sheet_name: str, credentials_dir: str
) -> gspread.Spreadsheet:
"""Create a spread sheet at the user's Drive directory.
Args:
new_sheet_name: The name of this spread sheet.
credentials_dir: The path to the directory that contains gspread
credentials files.
Returns:
An object of gspread.Spreadsheet.
"""
credentials = os.path.join(credentials_dir, 'credentials.json')
authorized_user = os.path.join(credentials_dir, 'authorized_user.json')
gc = gspread.oauth(credentials_filename=credentials,
authorized_user_filename=authorized_user)
sh = gc.create(new_sheet_name)
return sh
def _get_range_cell(
begin_row: int, begin_column: str, num_rows: int, num_columns: int
) -> str:
"""Get the sheet cell range in the string format.
Args:
begin_row: The begin row, in integer format.
begin_column: The begin column, in string format.
num_rows: Number of rows.
num_columns: Number of columns.
Return:
The range cell in the string format.
"""
end_row = begin_row + num_rows - 1
end_column = chr(ord(begin_column) + num_columns - 1)
return f'{begin_column}{begin_row}:{end_column}{end_row}'
def _write_compare_info(
sheet: gspread.Worksheet, report_names: List[str]
) -> None:
"""Write the compare information to a worksheet.
Args:
sheet: The object to worksheet for writing.
report_names: A list of cts report names.
"""
sheet.update_title('Test Info')
build_info = []
for i, name in enumerate(report_names):
build_info.append([f'Build {i}', name])
sheet.update(build_info)
def _write_compare_details(
sheet: gspread.Worksheet, compare_results: List[List[str]], start_row: int
) -> None:
"""Write the detailed comparison result to a worksheet.
Args:
sheet: The object to worksheet for writing.
compare_results: A list of comparison results.
start_row: The starting row for writing comparison results.
"""
curr_module = 'None'
curr_row = start_row
module_header_row = start_row
rows_content = []
module_header_formats = []
num_reports = len(compare_results[0]) - _NUM_OF_INFO_COLUMNS
module_failures = [0] * num_reports
for row_index, row_values in enumerate(compare_results):
module_name, abi, test_class, test_item, *test_statuses = row_values
module_end = ((row_index == len(compare_results) - 1) or
(module_name != compare_results[row_index + 1][0]))
# Module changes, need a new header row.
if module_name != curr_module:
module_with_abi = (module_name if abi == constant.ABI_IGNORED
else f'{module_name} [{abi}]')
rows_content.append([module_with_abi, ''] + [''] * num_reports)
module_header_row = len(rows_content)
header_cell = _get_range_cell(
begin_row=curr_row, begin_column='A',
num_rows=1, num_columns=len(rows_content[0]))
module_header_formats.append({
'range': header_cell,
'format': _MODULE_HEADER_FORMAT,
})
curr_row += 1
curr_module = module_name
for i, status in enumerate(test_statuses):
test_statuses[i] = '-' if status == 'pass' else status.upper()
if test_statuses[i] not in ['-', 'ASSUMPTION_FAILURE', 'NULL']:
module_failures[i] += 1
rows_content.append([test_class, test_item] + test_statuses)
curr_row += 1
# Module ends, update number of failed items in the header.
if module_end:
for index, count in enumerate(module_failures):
# The first two columns are for module info.
rows_content[module_header_row - 1][index + 2] = f'Failed: {count}'
module_failures = [0] * num_reports
if rows_content and module_header_formats:
content_cell = _get_range_cell(
begin_row=start_row, begin_column='A',
num_rows=len(rows_content), num_columns=len(rows_content[0]))
sheet.update(content_cell, rows_content)
sheet.batch_format(module_header_formats)
def main():
args = _parse_args()
# Get the comparison result
report_names, compare_results = _read_csv(args.compared_result)
# Create a google spread sheet
sheets = _create_spread_sheet(args.sheet_name, args.credentials_dir)
# Write test info to the fist worksheet
_write_compare_info(sheets.sheet1, report_names)
# Write comapre details to the second worksheet
# Limit the rows to len(compare_results) * 2 because we need module headers
detail_sheet = sheets.add_worksheet(
title='Detailed Comparison',
rows=len(compare_results) * 2,
cols=len(compare_results[0]))
# Format the first row
row_header = ['Test Class', 'Test Item'] + report_names
cell = _get_range_cell(
begin_row=1, begin_column='A', num_rows=1, num_columns=len(row_header))
detail_sheet.update(cell, [row_header])
detail_sheet.format(cell, _SHEET_HEADER_FORMAT)
# write details to the worksheet, starting at the second row
_write_compare_details(detail_sheet, compare_results, 2)
if __name__ == '__main__':
main()