You've already forked open-source-firmware-validation
mirror of
https://github.com/Dasharo/open-source-firmware-validation.git
synced 2026-03-06 14:51:55 -08:00
38906581c4
* add git-cliff and reuse Files that do not support comments or that have problems adding comments at the first line should have a separate .license file or a rule inside REUSE.toml (in case there are a lot of such files). .robot files generally support comments at the first line, but robotidy does not want comments to start at first line. It wants so, that everything that is located before first section should be placed inside "Comments" section. But reuse does not support license headers in any sections. So reuse and robotidy have a conflict here. Because there are a lot of .robot files, I have decided to add them into REUSE.toml instead of separate .license files or robotidy exceptions. Signed-off-by: Daniil Klimuk <daniil.klimuk@3mdeb.com> * add LICENSES and license headers to files Files that does not have license headers have either .license file or a rule inside REUSE.toml. Signed-off-by: Daniil Klimuk <daniil.klimuk@3mdeb.com> * .github: ISSUE_TEMPLATE: fix markdownlint Signed-off-by: Daniil Klimuk <daniil.klimuk@3mdeb.com> * README: add git-cliff and reuse Signed-off-by: Daniil Klimuk <daniil.klimuk@3mdeb.com> --------- Signed-off-by: Daniil Klimuk <daniil.klimuk@3mdeb.com>
196 lines
6.7 KiB
Python
Executable File
196 lines
6.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: 2024 3mdeb <contact@3mdeb.com>
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import argparse
|
|
import time
|
|
|
|
import gspread
|
|
from gspread.exceptions import APIError
|
|
from oauth2client.service_account import ServiceAccountCredentials
|
|
from robot.api import ExecutionResult, ResultVisitor
|
|
|
|
# Global variables
|
|
SPREADSHEET_URL = "https://docs.google.com/spreadsheets/d/1wSE6xA3K3nXewwLn5lV39_2wZL1kg5AkGb4mvmG3bwE"
|
|
WORKSHEET_NAME = "Results"
|
|
CREDS_FILE = "spreadsheet-creds.json"
|
|
|
|
|
|
class MyResultVisitor(ResultVisitor):
|
|
def __init__(self):
|
|
self.results = {}
|
|
|
|
def visit_test(self, test):
|
|
test_id = test.name.split()[
|
|
0
|
|
] # Assuming Test ID is the first part of the test name
|
|
self.results[test_id] = test.status
|
|
|
|
|
|
def retry_function(func, *args, **kwargs):
|
|
while True:
|
|
try:
|
|
return func(*args, **kwargs)
|
|
except APIError as e:
|
|
if e.response.status_code == 429: # Rate limit exceeded
|
|
print(f"Rate limit exceeded. Waiting and retrying...")
|
|
time.sleep(10) # Wait for 10 seconds before retrying
|
|
else:
|
|
raise # Rethrow any other APIError
|
|
|
|
|
|
def read_cell(sheet, row, col):
|
|
return retry_function(sheet.cell, row, col).value.strip()
|
|
|
|
|
|
def update_cell(sheet, row, col, value):
|
|
retry_function(sheet.update_cell, row, col, value)
|
|
|
|
|
|
def update_spreadsheet(results, version_header, verbose=False):
|
|
scope = [
|
|
"https://spreadsheets.google.com/feeds",
|
|
"https://www.googleapis.com/auth/drive",
|
|
]
|
|
creds = ServiceAccountCredentials.from_json_keyfile_name(CREDS_FILE, scope)
|
|
client = gspread.authorize(creds)
|
|
sheet = client.open_by_url(SPREADSHEET_URL).worksheet(WORKSHEET_NAME)
|
|
|
|
# Find the appropriate column for the given version header
|
|
version_column = find_version_column(sheet, version_header)
|
|
|
|
# Get all test IDs from the spreadsheet
|
|
test_ids_raw = retry_function(
|
|
sheet.col_values, 2
|
|
) # Assuming Test IDs are in the second column
|
|
|
|
# Strip whitespace from all test IDs in the spreadsheet to normalize
|
|
test_ids = [test_id.strip() for test_id in test_ids_raw]
|
|
|
|
overwrite_all = False # Flag to track if user wants to overwrite all future cells
|
|
|
|
# Iterate over the results dictionary to update the spreadsheet
|
|
for test_id, status in results.items():
|
|
# Find the row number for the current test ID in the spreadsheet
|
|
try:
|
|
row_num = (
|
|
test_ids.index(test_id) + 1
|
|
) # Adjust for 1-based indexing in Google Sheets
|
|
|
|
# Read current value from the cell
|
|
current_value = read_cell(sheet, row_num, version_column)
|
|
|
|
if current_value == status:
|
|
if verbose:
|
|
print(
|
|
f"{test_id}: Cell in Row {row_num}, Column {version_column} already contains '{status}'. Skipping update."
|
|
)
|
|
continue # Skip update if current content matches the result
|
|
|
|
if current_value and overwrite_all is False:
|
|
print(
|
|
f"{test_id}: Cell in Row {row_num}, Column {version_column} is already populated with: '{current_value}'"
|
|
)
|
|
while True:
|
|
confirmation = (
|
|
input(
|
|
f"Do you want to overwrite this cell with: {status}? [(y)es,(n)o,(a)ll,(e)xit]: "
|
|
)
|
|
.strip()
|
|
.lower()
|
|
)
|
|
if confirmation in ["y", "n", "a", "e", "yes", "no", "all," "exit"]:
|
|
break # Exit the loop if a valid answer is given
|
|
else:
|
|
print("Please enter a valid option [(y)es,(n)o,(a)ll,(e)xit].")
|
|
|
|
if confirmation == "n" or confirmation == "no":
|
|
continue # Skip this update
|
|
elif confirmation == "a" or confirmation == "all":
|
|
overwrite_all = True
|
|
elif confirmation == "e":
|
|
break # Stop updating cells and exit
|
|
|
|
# Update the cell with the new value
|
|
update_cell(sheet, row_num, version_column, status)
|
|
if verbose:
|
|
print(
|
|
f"Updated cell: Row {row_num}, Column {version_column} with Status '{status}' for Test ID '{test_id}'"
|
|
)
|
|
|
|
except ValueError:
|
|
print(f"Test ID '{test_id}' not found in the spreadsheet. Skipping update.")
|
|
|
|
|
|
def find_version_column(sheet, version_header):
|
|
header_row = retry_function(sheet.row_values, 2)
|
|
if version_header in header_row:
|
|
return header_row.index(version_header) + 1
|
|
else:
|
|
raise ValueError(
|
|
f"Version header '{version_header}' not found in the spreadsheet."
|
|
)
|
|
|
|
|
|
def parse_robot_results(xml_file):
|
|
visitor = MyResultVisitor()
|
|
result = ExecutionResult(xml_file)
|
|
result.visit(visitor)
|
|
return visitor.results
|
|
|
|
|
|
def update_command(args):
|
|
# Parse the Robot Framework results
|
|
results = parse_robot_results(args.xml_file)
|
|
|
|
# Join version_header into a single string
|
|
version_header = " ".join(args.version_header)
|
|
|
|
# Update the spreadsheet with the parsed results
|
|
update_spreadsheet(results, version_header, verbose=args.verbose)
|
|
|
|
|
|
def download_command(args):
|
|
# Placeholder for download command implementation
|
|
print("Download command is not implemented yet.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(
|
|
description="Manage Open Source Firmware Validation results in Google Sheets."
|
|
)
|
|
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
|
|
# Update command parser
|
|
update_parser = subparsers.add_parser(
|
|
"update", help="Update spreadsheet with Robot Framework results."
|
|
)
|
|
update_parser.add_argument(
|
|
"xml_file", help="Path to the Robot Framework XML results file."
|
|
)
|
|
update_parser.add_argument(
|
|
"version_header",
|
|
nargs="+",
|
|
help="Header name of the version column to update (enclose in quotes).",
|
|
)
|
|
update_parser.add_argument(
|
|
"--verbose", action="store_true", help="Enable verbose logging for updates."
|
|
)
|
|
|
|
# Download command parser (placeholder)
|
|
download_parser = subparsers.add_parser(
|
|
"download", help="Download results from Google Sheets (not implemented yet)."
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Execute the appropriate command based on user input
|
|
if args.command == "update":
|
|
update_command(args)
|
|
elif args.command == "download":
|
|
download_command(args)
|
|
else:
|
|
parser.print_help()
|