github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/spyglass/lenses/coverage/coverage.ts (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 import Color from "color"; 18 import {inflate} from "pako/lib/inflate"; 19 import {Coverage, parseCoverage} from './parser'; 20 21 declare const COVERAGE_FILE: string; 22 declare const RENDERED_COVERAGE_URL: string; 23 24 const NO_COVERAGE = Color('#FF0000'); 25 const FULL_COVERAGE = Color('#00FF00'); 26 27 // Inspired by https://dl.acm.org/citation.cfm?id=949654 28 function renderChildren(parent: Node, coverage: Coverage, horizontal: boolean): void { 29 let offset = 0; 30 for (const child of coverage.children.values()) { 31 const node = document.createElement('a'); 32 node.style.display = 'block'; 33 parent.appendChild(node); 34 const percentage = child.totalStatements / coverage.totalStatements * 100; 35 node.style.position = 'absolute'; 36 if (horizontal) { 37 node.style.width = `${percentage}%`; 38 node.style.height = '100%'; 39 node.style.top = '0'; 40 node.style.left = `${offset}%`; 41 } else { 42 node.style.width = '100%'; 43 node.style.height = `${percentage}%`; 44 node.style.top = `${offset}%`; 45 node.style.left = `0`; 46 } 47 offset += percentage; 48 if (child.totalFiles === 1) { 49 node.classList.add('leaf'); 50 const [filename, file] = child.files.entries().next().value; 51 node.title = `${filename}: ${(file.coveredStatements / file.totalStatements * 100).toFixed(0)}%`; 52 53 const bgColor = NO_COVERAGE.mix(FULL_COVERAGE, file.coveredStatements / file.totalStatements); 54 node.style.backgroundColor = bgColor.hex(); 55 // Not having a border looks weird, but using a constant colour causes tiny boxes 56 // to consist entirely of that colour. By using a border colour based on the 57 // box colour, we still show some information. 58 node.style.borderColor = bgColor.darken(0.3).hex(); 59 60 if (RENDERED_COVERAGE_URL) { 61 node.href = `${RENDERED_COVERAGE_URL}#file${file.fileNumber}`; 62 } 63 } else { 64 renderChildren(node, child, !horizontal); 65 } 66 } 67 } 68 69 window.onload = () => { 70 // Because the coverage files are a) huge, and b) compress excellently, we send it as 71 // gzipped base64. This is faster unless your internet connection is faster than 72 // about 300 Mb/s. 73 const content = inflate(atob(COVERAGE_FILE), {to: 'string'}); 74 const coverage = parseCoverage(content); 75 document.getElementById('statement-coverage')!.innerText = `${(coverage.coveredStatements / coverage.totalStatements * 100).toFixed(0)}% (${coverage.coveredStatements.toLocaleString()} of ${coverage.totalStatements.toLocaleString()} statements)`; 76 document.getElementById('file-coverage')!.innerText = `${(coverage.coveredFiles / coverage.totalFiles * 100).toFixed(0)}% (${coverage.coveredFiles.toLocaleString()} of ${coverage.totalFiles.toLocaleString()} files)`; 77 const treemapEl = document.getElementById('treemap')!; 78 renderChildren(treemapEl, coverage, true); 79 if (RENDERED_COVERAGE_URL) { 80 treemapEl.classList.add('interactive'); 81 } 82 };