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  };