blob: 83b8edc2ede8b635ea16b3384b5ecee9f59c816d [file] [log] [blame]
// Copyright (C) 2022 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.
// Helper function to create DOM elements faster: takes a Mithril-style
// "selector" of the form "tag.class1.class2" and a list of child objects that
// can be either strings or DOM elements.
function m(selector, ...children) {
const parts = selector.split('.');
if (parts.length === 0) {
throw new Error(
'Selector passed to element should be of a form tag.class1.class2');
}
const result = document.createElement(parts[0]);
for (let i = 1; i < parts.length; i++) {
result.classList.add(parts[i]);
}
for (const child of children) {
if (typeof child === 'string') {
const childNode = document.createTextNode(child);
result.appendChild(childNode);
} else {
result.appendChild(child);
}
}
return result;
}
function getCiRun() {
const url = new URL(window.location.href);
const parts = url.pathname.split('/');
// Example report URL:
// https://storage.googleapis.com/perfetto-ci-artifacts/20220711123401--cls-2149676-1--ui-clang-x86_64-release/ui-test-artifacts/index.html
// Parts would contain ['', 'perfetto-ci-artifacts',
// '20220711123401--cls-2149676-1--ui-clang-x86_64-release', ...] in this
// case, which means that we need to check length of the array and get third
// element out of it.
if (parts.length >= 3) {
return parts[2];
}
return null;
}
function imageLinkElement(path) {
const img = m('img');
img.src = path;
const link = m('a');
link.appendChild(img);
link.href = path;
link.target = '_blank';
return link;
}
function processLines(lines) {
const container = document.querySelector('.container');
container.innerHTML = '';
const children = [];
// report.txt is a text file with a pair of file names on each line, separated
// by semicolon. E.g. "screenshot.png;screenshot-diff.png"
for (const line of lines) {
// Skip empty lines (happens when the file is completely empty).
if (line.length === 0) {
continue;
}
const parts = line.split(';');
if (parts.length !== 2) {
console.warn(
`Malformed line (expected two files separated via semicolon) ${
line}!`);
continue;
}
const [output, diff] = parts;
children.push(m(
'div.row',
m('div.cell', output, m('div.image-wrapper', imageLinkElement(output))),
m('div.cell', diff, m('div.image-wrapper', imageLinkElement(diff)))));
}
if (children.length === 0) {
container.appendChild(m('div', 'All good!'));
return;
}
const run = getCiRun();
if (run !== null) {
const cmd = `tools/download_changed_screenshots.py ${run}`;
const button = m('button', 'Copy');
button.addEventListener('click', async () => {
await navigator.clipboard.writeText(cmd);
button.innerText = 'Copied!';
});
container.appendChild(m(
'div.message',
'Use following command from Perfetto checkout directory to apply the ' +
'changes: ',
m('span.cmd', cmd),
button));
}
for (const child of children) {
container.appendChild(child);
}
}
async function loadDiffs() {
try {
const report = await fetch('report.txt');
const response = await report.text();
processLines(response.split('\n'));
} catch (e) {
// report.txt is not available when all tests have succeeded, treat fetching
// error as absence of failures
processLines([]);
}
}
document.addEventListener('DOMContentLoaded', () => {
loadDiffs();
});