blob: 83e9b39e4477b39e89491a55c6d286c83ddeb7d4 [file] [edit]
#!/usr/bin/env python3
# Copyright (c) 2026, the R8 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.
"""Deploys the weekly perf page and its main history to GCS.
The page loads the weekly result bundles that tools/perf.py writes directly
from the bucket, and uses commits.json to order the main commits.
"""
import argparse
import datetime
import json
import os
import pathlib
import re
import subprocess
import sys
SCRIPT_DIR = pathlib.Path(__file__).resolve().parent
TOOLS_DIR = SCRIPT_DIR.parent
REPO_ROOT = TOOLS_DIR.parent
if str(TOOLS_DIR) not in sys.path:
sys.path.insert(0, str(TOOLS_DIR))
import r8_release
import utils
DEFAULT_BUCKET = 'r8-test-results'
DEFAULT_PREFIX = 'perf'
STATIC_SUFFIXES = ('.html', '.js', '.css')
# Enough main history for all backfilled results and release cuts.
MAIN_HISTORY_COMMITS = 5000
OLDEST_RELEASE_CUT = (8, 4)
RELEASE_BRANCH_RE = re.compile(r'^origin/(\d+)\.(\d+)$')
CACHE_HEADER = 'Cache-Control: no-cache, max-age=0'
def git_output(args):
return subprocess.check_output(
['git', '-C', str(REPO_ROOT), *args], text=True)
def read_main_history():
output = git_output([
'log', '--first-parent', f'-n{MAIN_HISTORY_COMMITS}',
'--format=%H%x09%an%x09%ct%x09%s', 'origin/main'
])
commits = []
for line in output.splitlines():
parts = line.split('\t', 3)
if len(parts) != 4:
continue
commit_hash, author, timestamp, title = parts
commits.append({
'author': author,
'hash': commit_hash,
'submitted': int(timestamp),
'title': title,
})
return commits
def read_release_cuts():
dev_branch_tuple = tuple(
int(p) for p in r8_release.R8_DEV_BRANCH.split('.'))
refs_output = git_output(
['for-each-ref', '--format=%(refname:short)', 'refs/remotes/origin'])
versions = []
for ref in refs_output.splitlines():
m = RELEASE_BRANCH_RE.match(ref)
if not m:
continue
version = (int(m.group(1)), int(m.group(2)))
if OLDEST_RELEASE_CUT <= version < dev_branch_tuple:
versions.append(version)
versions.sort(reverse=True)
cuts = []
for major, minor in versions:
branch = f'{major}.{minor}'
cut_hash = git_output(['merge-base', f'origin/{branch}',
'origin/main']).strip()
if not cut_hash:
continue
meta_lines = git_output(
['show', '-s', '--format=%an%x09%ct%x09%s', cut_hash]).splitlines()
if not meta_lines:
continue
parts = meta_lines[0].split('\t', 2)
if len(parts) != 3:
continue
author, timestamp, title = parts
cuts.append({
'branch': branch,
'hash': cut_hash,
'author': author,
'submitted': int(timestamp),
'title': title,
})
return cuts
def build_commits_data():
return {
'generated_at':
datetime.datetime.now(datetime.timezone.utc).isoformat(),
'dev_branch':
r8_release.R8_DEV_BRANCH,
'release_cuts':
read_release_cuts(),
'main':
read_main_history(),
}
def deploy_perf_page(bucket=DEFAULT_BUCKET, prefix=DEFAULT_PREFIX):
gcs_root = f'gs://{bucket}/{prefix.strip("/")}'
with utils.TempDir(prefix='r8_perf_weekly_') as tmp_dir:
commits_file = os.path.join(tmp_dir, 'commits.json')
with open(commits_file, 'w', encoding='utf-8') as f:
json.dump(build_commits_data(), f)
files = [
str(path)
for path in sorted(SCRIPT_DIR.iterdir())
if path.suffix in STATIC_SUFFIXES
] + [commits_file]
for src in files:
utils.upload_file_to_cloud_storage(
src, f'{gcs_root}/{os.path.basename(src)}', header=CACHE_HEADER)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--bucket', default=DEFAULT_BUCKET)
parser.add_argument('--prefix', default=DEFAULT_PREFIX)
args = parser.parse_args()
deploy_perf_page(bucket=args.bucket, prefix=args.prefix)
return 0
if __name__ == '__main__':
sys.exit(main())