2022-01-06 21:35:02 +00:00
|
|
|
<html id="html">
|
2021-12-25 17:21:30 +00:00
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
2022-01-06 21:35:02 +00:00
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
color: white;
|
|
|
|
background: black;
|
|
|
|
font-family: sans-serif;
|
|
|
|
}
|
|
|
|
|
|
|
|
#loading {
|
|
|
|
margin-top: 1em;
|
|
|
|
}
|
|
|
|
|
|
|
|
#loading img {
|
|
|
|
width: 130px;
|
|
|
|
display: block;
|
|
|
|
margin: 30px auto;
|
|
|
|
-webkit-animation: spin 2s ease-in-out infinite;
|
|
|
|
-moz-animation: spin 2s ease-in-out infinite;
|
|
|
|
animation: spin 2s ease-in-out infinite;
|
|
|
|
}
|
|
|
|
|
|
|
|
#loading h1 {
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
#info {
|
|
|
|
position: sticky;
|
|
|
|
top: 1rem;
|
|
|
|
z-index: 1;
|
|
|
|
margin: 1rem;
|
|
|
|
float: right;
|
|
|
|
font-size: 16pt;
|
|
|
|
padding: 0.5rem;
|
|
|
|
border: 1px solid #111;
|
|
|
|
border-radius: 10px;
|
|
|
|
box-shadow: white 5px 5px 28px -10px;
|
|
|
|
display: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas {
|
|
|
|
position: absolute;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
@-moz-keyframes spin {
|
|
|
|
100% { -moz-transform: rotate(360deg); }
|
|
|
|
}
|
|
|
|
|
|
|
|
@-webkit-keyframes spin {
|
|
|
|
100% { -webkit-transform: rotate(360deg); }
|
|
|
|
}
|
|
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
100% { transform:rotate(360deg); }
|
|
|
|
}
|
|
|
|
</style>
|
2021-12-25 17:21:30 +00:00
|
|
|
</head>
|
2022-01-06 21:35:02 +00:00
|
|
|
<body>
|
|
|
|
<div id="loading">
|
|
|
|
<img src="https://clickhouse.com/images/logo.svg">
|
|
|
|
<h1>Loading (~10 seconds, try load ~20 MB)</h1>
|
|
|
|
</div>
|
|
|
|
<pre id="info"></pre>
|
|
|
|
<canvas id="canvas"></canvas>
|
2021-12-25 17:21:30 +00:00
|
|
|
<script type="text/javascript">
|
2022-01-06 21:35:02 +00:00
|
|
|
///////////////////////
|
|
|
|
// GLOBAL VARIABLES
|
|
|
|
///////////////////////
|
2021-12-25 17:21:30 +00:00
|
|
|
let start_date = '2020-06-13';
|
2022-01-06 21:35:02 +00:00
|
|
|
const canvasNode = document.getElementById('canvas');
|
|
|
|
const infoNode = document.getElementById('info');
|
|
|
|
const loadingNode = document.getElementById('loading');
|
|
|
|
|
|
|
|
///////////////////////
|
|
|
|
// QUERIES
|
|
|
|
///////////////////////
|
|
|
|
let render_data_query = `
|
2021-12-25 17:21:30 +00:00
|
|
|
WITH '${start_date}'::Date AS start_date
|
|
|
|
SELECT groupArray([d, n, fail]) FROM
|
|
|
|
(
|
|
|
|
SELECT n, check_start_time::Date - start_date AS d, max(test_status LIKE 'F%' OR test_status LIKE 'E%') AS fail
|
|
|
|
FROM "gh-data".checks
|
|
|
|
|
|
|
|
INNER JOIN
|
|
|
|
(
|
|
|
|
SELECT test_name, toUInt16(rowNumberInAllBlocks()) AS n FROM
|
|
|
|
(
|
|
|
|
SELECT DISTINCT test_name
|
|
|
|
FROM "gh-data".checks
|
|
|
|
WHERE match(test_name, '^\\d+_') AND check_name ILIKE '%stateless%' AND check_start_time > now() - INTERVAL 1 DAY
|
|
|
|
ORDER BY test_name
|
|
|
|
)
|
|
|
|
) AS nums
|
|
|
|
|
|
|
|
USING (test_name)
|
|
|
|
|
|
|
|
WHERE
|
|
|
|
check_name ILIKE '%stateless%'
|
|
|
|
AND pull_request_number = 0
|
|
|
|
AND check_start_time >= start_date
|
|
|
|
GROUP BY d, n
|
|
|
|
ORDER BY d, n
|
|
|
|
)
|
|
|
|
FORMAT TSV`;
|
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
let test_names_query = `
|
|
|
|
SELECT test_name, toUInt16(rowNumberInAllBlocks()) AS n FROM
|
|
|
|
(
|
|
|
|
SELECT DISTINCT test_name
|
|
|
|
FROM "gh-data".checks
|
|
|
|
WHERE match(test_name, '^\\d+_') AND check_name ILIKE '%stateless%' AND check_start_time > now() - INTERVAL 1 DAY
|
|
|
|
ORDER BY test_name
|
|
|
|
) FORMAT JSONCompact`
|
|
|
|
|
|
|
|
///////////////////////
|
|
|
|
// MAIN
|
|
|
|
///////////////////////
|
|
|
|
|
|
|
|
Promise.all([
|
|
|
|
invokeCbWithDataByQuery(render_data_query, renderResponse),
|
|
|
|
invokeCbWithDataByQuery(test_names_query, saveTestNames),
|
|
|
|
])
|
|
|
|
.then(hideLoader)
|
|
|
|
.catch(alert);
|
|
|
|
|
|
|
|
///////////////////////
|
|
|
|
// SPECIAL FUNCTIONS
|
|
|
|
///////////////////////
|
|
|
|
|
|
|
|
async function invokeCbWithDataByQuery(query, callback) {
|
|
|
|
data = await loadDataByQuery(query);
|
|
|
|
callback(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function loadDataByQuery(query) {
|
|
|
|
const response = await fetch(
|
2022-01-06 19:06:56 +00:00
|
|
|
"https://play-ci.clickhouse.com?user=play&add_http_cors_header=1",
|
|
|
|
{ method: "POST", body: query }
|
|
|
|
)
|
2022-01-06 21:35:02 +00:00
|
|
|
if (!response.ok) throw new Error(`Data download failed\nHTTP status ${response.status}`);
|
|
|
|
const json = await response.json();
|
|
|
|
return json;
|
2021-12-25 17:21:30 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
function renderResponse(data) {
|
2021-12-25 17:21:30 +00:00
|
|
|
const last_pixel = data[data.length - 1];
|
2022-01-06 21:35:02 +00:00
|
|
|
canvasNode.width = last_pixel[0] + 1;
|
|
|
|
canvasNode.height = last_pixel[1] + 1;
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
document.getElementById('html').style.height = canvasNode.height + 10 + 'px';
|
|
|
|
document.body.style.height = canvasNode.height + 10 + 'px';
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
let ctx = canvasNode.getContext('2d');
|
|
|
|
let image = ctx.createImageData(canvasNode.width, canvasNode.height);
|
|
|
|
let {data: pixels} = image;
|
2021-12-25 17:21:30 +00:00
|
|
|
|
|
|
|
data.map(elem => {
|
|
|
|
let x = elem[0];
|
2022-01-06 21:35:02 +00:00
|
|
|
let y = canvasNode.height - elem[1];
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
pixels[(x + y * canvasNode.width) * 4 + 0] = elem[2] ? 255 : 0; // r
|
|
|
|
pixels[(x + y * canvasNode.width) * 4 + 1] = elem[2] ? 0 : 100; // g
|
|
|
|
pixels[(x + y * canvasNode.width) * 4 + 2] = 0; // b
|
|
|
|
pixels[(x + y * canvasNode.width) * 4 + 3] = 255; // a
|
2021-12-25 17:21:30 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
ctx.putImageData(image, 0, 0);
|
|
|
|
}
|
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
function saveTestNames(data) {
|
|
|
|
let {data: test_names} = data;
|
|
|
|
infoNode.style.display = 'block';
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
canvasNode.addEventListener('mousemove', (event) => {
|
|
|
|
const x = event.layerX;
|
|
|
|
const y = event.layerY;
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
let date = new Date(start_date);
|
|
|
|
date.setDate(date.getDate() + x);
|
|
|
|
[date] = date.toISOString().split('T');
|
|
|
|
let [test] = test_names[canvasNode.height - y];
|
|
|
|
let {data: pixel} = canvasNode.getContext('2d').getImageData(x, y, 1, 1);
|
|
|
|
updateInfo(date, test, pixel);
|
|
|
|
})
|
2021-12-25 17:21:30 +00:00
|
|
|
}
|
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
function updateInfo(date, test, pixel) {
|
|
|
|
infoNode.innerText = `${date}, ${test}`;
|
|
|
|
infoNode.style.background = pixel[0] > 0 ? '#F00' : (pixel[3] > 0 ? '#006400' : '#000');
|
|
|
|
}
|
2021-12-25 17:21:30 +00:00
|
|
|
|
2022-01-06 21:35:02 +00:00
|
|
|
function hideLoader() {
|
|
|
|
loadingNode.style.display = 'none';
|
|
|
|
}
|
2021-12-25 17:21:30 +00:00
|
|
|
|
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|