blob: a3b74ba25deb3d1681931ad880203e37416ab01f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
#
"""Tool to automatically update the DartFuzzStats spreadsheet
Requires a one-time authentication step with a @google account.
"""
from __future__ import print_function
import pickle
import os.path
import subprocess
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# This script may require a one time install of Google API libraries:
# pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
# The ID and range of a spreadsheet.
SPREADSHEET_ID = '1nDoK-dCuEmf6yo55a303UClRd7AwjbzPkRr37ijWcC8'
RANGE_NAME = 'Sheet1!A3:H'
VERIFY_CURRENT_ROW_FORMULA = '=B:B-C:C-D:D-E:E-F:F'
def authenticate():
dir_path = os.path.dirname(os.path.realpath(__file__))
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
pickle_path = os.path.join(dir_path, 'token.pickle')
if os.path.exists(pickle_path):
with open(pickle_path, 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
os.path.join(dir_path, 'credentials.json'), SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(pickle_path, 'wb') as token:
pickle.dump(creds, token)
return build('sheets', 'v4', credentials=creds)
# Returns the next run ID based on the last run ID found in the fuzzing
# spreadsheet.
def get_next_run_id(sheet):
result = sheet.values().get(
spreadsheetId=SPREADSHEET_ID, range=RANGE_NAME).execute()
values = result.get('values', [])
return int(values[-1][0]) + 1
# Inserts a new entry into the fuzzing spreadsheet.
def add_new_fuzzing_entry(sheet, run, tests, success, rerun, skipped, timeout,
divergences):
entry = [run, tests, success, skipped, timeout, divergences, rerun]
print(
'Adding entry for run %d. Tests: %d Successes: %d Skipped: %d Timeouts: %d, Divergences: %d Re-runs: %d'
% tuple(entry))
values = {'values': [entry + [VERIFY_CURRENT_ROW_FORMULA]]}
sheet.values().append(
spreadsheetId=SPREADSHEET_ID,
range=RANGE_NAME,
body=values,
valueInputOption='USER_ENTERED').execute()
# Scrapes the fuzzing shards for fuzzing run statistics.
#
# Returns a list of statistics in the following order:
#
# - # of tests
# - # of successes
# - # of re-runs
# - # of skipped runs
# - # of timeouts
# - # of divergences
#
def get_run_statistic_summary(run):
dir_path = os.path.dirname(os.path.realpath(__file__))
output = subprocess.check_output([
'python3',
os.path.join(dir_path, 'collect_data.py'), '--output-csv', '--type=sum',
'https://ci.chromium.org/p/dart/builders/ci.sandbox/fuzz-linux/%d' % run
])
return list(map(int, output.decode('UTF-8').rstrip().split(',')))
def main():
service = authenticate()
# Call the Sheets API
sheet = service.spreadsheets()
while True:
try:
next_id = get_next_run_id(sheet)
summary = get_run_statistic_summary(next_id)
add_new_fuzzing_entry(sheet, next_id, *summary)
except:
# get_run_statistic_summary exits with non-zero exit code if we're out
# of runs to check.
print('No more runs to process. Exiting.')
break
if __name__ == '__main__':
main()