OXYGENHUB
# b9eb70fb9509 oxygenhub / templates / coverage.html
8.1 KiB · HTML · last changed Coverage from a workstation: oh coverage upload, shown as uploaded 25 days ago source blame history raw
554ccacf Andy McCall ↶ 1
{% extends "base.html" %}
2
{% import "repo_tabs.html" as m %}
3
{% block title %}Coverage · {{ repo.owner }}/{{ repo.name }}{% endblock %}
4
{% block tabs %}{% call m::tabs(repo, "coverage") %}{% endblock %}
5
{% block content %}
6
{% if let Some(r) = report %}
c987c865 Andy McCall ↶ 7
<section class="cov-hero">
8
  <div class="cov-hero-head">
9
    <div>
10
      <h1>Coverage</h1>
11
      <div class="cov-sub">{% if bookmarks.len() > 1 %}<form class="inline" method="get" action="{{ repo.url }}/coverage"><label for="cov-bm" class="mute">bookmark</label> <select id="cov-bm" name="bookmark" onchange="this.form.submit()">{% for b in bookmarks %}<option value="{{ b }}"{% if b.as_str() == bookmark.as_str() %} selected{% endif %}>{{ b }}</option>{% endfor %}</select> <noscript><button>Show</button></noscript></form>{% else %}<span class="mute">on</span> <strong>{{ bookmark }}</strong>{% endif %}
40dd3f86 Andy McCall ↶ 12
        · {% if r.uploaded() %}<span class="tag warn" title="Uploaded with oh coverage upload: measured off the hub, not by a Flow job">uploaded by {{ r.uploader }}</span>{% else %}<a href="{{ repo.url }}/flow/{{ r.run_number }}">run #{{ r.run_number }}</a>{% endif %} · <time title="{{ r.created_ms|when_i }}">{{ r.created_ms|ago_i }}</time></div>
c987c865 Andy McCall ↶ 13
    </div>
14
    <div class="cov-score {{ self.class_of(r.percent()) }}">
15
      <div class="cov-big">{{ self.pct(r.percent()) }}</div>
40dd3f86 Andy McCall ↶ 16
      {% if let Some(d) = delta %}<div class="cov-change {{ self.delta_class(d) }}" title="Against {% if let Some(p) = previous %}{{ p.source() }}{% endif %}">{{ self.signed(d) }} since the run before</div>{% else %}<div class="cov-change same">the first report here</div>{% endif %}
c987c865 Andy McCall ↶ 17
    </div>
18
  </div>
19
  {% if runs > 1 %}<div class="cov-hero-chart">{{ coverage_chart|safe }}</div>{% endif %}
20
</section>
21
22
<section class="cov-facts">
23
  <div><span class="k">Lines covered</span><span class="v">{{ r.lines_hit }} <small>of {{ r.lines_found }}</small></span></div>
24
  <div><span class="k">Hits per line</span><span class="v">{{ self.hits(r) }}</span></div>
25
  {% if r.functions_found > 0 %}<div><span class="k">Functions</span><span class="v">{{ self.pct(r.functions_percent()) }} <small>{{ r.functions_hit }} of {{ r.functions_found }}</small></span></div>{% endif %}
26
  {% if r.branches_found > 0 %}<div><span class="k">Branches</span><span class="v">{{ self.pct(r.branches_percent()) }} <small>{{ r.branches_hit }} of {{ r.branches_found }}</small></span></div>{% endif %}
27
  <div><span class="k">Files</span><span class="v">{{ r.files }}</span></div>
28
  {% if let Some(t) = first_ms %}<div><span class="k">Reporting since</span><span class="v small"><time title="{{ t|when_i }}">{{ t|ago_i }}</time></span></div>{% endif %}
29
  <div><span class="k">Badge</span><span class="v"><img src="{{ repo.url }}/coverage/badge.svg" alt="coverage {{ self.pct(r.percent()) }}" class="cov-badge"><button type="button" class="cov-copy" data-copy="[![coverage]({{ shell.base_url }}{{ repo.url }}/coverage/badge.svg)]({{ shell.base_url }}{{ repo.url }}/coverage)" title="Copy the Markdown for a README">copy Markdown</button></span></div>
554ccacf Andy McCall ↶ 30
</section>
c987c865 Andy McCall ↶ 31
32
<div class="cov-grid">
33
  <section class="panel cov-card">
34
    <h2>This run</h2>
35
    <ul class="cov-stats">
36
      <li><strong>{{ r.lines_hit }}</strong> of <strong>{{ r.lines_found }}</strong> relevant lines covered <span class="{{ self.class_of(r.percent()) }}">({{ self.pct(r.percent()) }})</span></li>
40dd3f86 Andy McCall ↶ 37
      {% if let Some((found, hit)) = self.lines_delta() %}<li>{% if *found >= 0 %}+{% endif %}{{ found }} relevant lines, {% if *hit >= 0 %}+{% endif %}{{ hit }} covered, against {% if let Some(p) = previous %}{{ p.source() }}{% endif %}</li>{% endif %}
c987c865 Andy McCall ↶ 38
      <li><strong>{{ self.hits(r) }}</strong> hits per line</li>
40dd3f86 Andy McCall ↶ 39
      <li>{% if r.uploaded() %}Uploaded by <strong>{{ r.uploader }}</strong>, measured off the hub{% else %}Job <strong>{{ r.job }}</strong>{% endif %}{% if r.dropped > 0 %}; {{ r.dropped }} files the report named are not in this state and are left out{% endif %}</li>
c987c865 Andy McCall ↶ 40
      {% if added > 0 %}<li>{{ added }} new files</li>{% endif %}
41
    </ul>
42
    {% if !moved.is_empty() %}<h3>Coverage moved in</h3>
43
    <table class="cov-moved">{% for f in moved %}<tr><td><a href="{{ repo.url }}/coverage/{{ r.id }}/file/{{ f.path }}">{{ f.path }}</a></td><td class="num mute">{{ self.pct_of(f.before) }} → {{ self.pct_of(f.after) }}</td><td class="num cov-change {{ self.delta_class(&f.delta) }}">{{ self.signed(&f.delta) }}</td></tr>{% endfor %}</table>{% endif %}
44
  </section>
45
  <section class="panel cov-card">
46
    <h2>Files by coverage</h2>
47
    <div class="cov-bands">{% for b in bands %}<div class="cov-band"><span class="cov-band-lbl">{{ b.label }}</span><span class="bar {{ b.class }}"><span style="width: {{ b.width }}%"></span></span><span class="n">{{ b.files }}</span></div>{% endfor %}</div>
48
  </section>
49
</div>
50
51
{% if runs > 1 %}<section class="panel">
52
  <h2>Relevant lines covered <small class="mute"><span class="cov-key covered">covered</span> <span class="cov-key relevant">missed</span></small></h2>
53
  {{ lines_chart|safe }}
54
</section>{% endif %}
55
56
{% if recent.len() > 1 %}<section class="panel">
57
  <h2>Recent runs on {{ bookmark }}</h2>
58
  <div class="table"><table class="cov-runs">
59
  <tr><th>Run</th><th>Job</th><th>Coverage</th><th class="num">Change</th><th class="num">Lines</th><th>When</th></tr>
60
  {% for x in recent %}<tr{% if x.report.id == r.id %} class="on"{% endif %}>
40dd3f86 Andy McCall ↶ 61
    <td><a href="{{ repo.url }}/coverage?report={{ x.report.id }}">{% if x.report.uploaded() %}upload by {{ x.report.uploader }}{% else %}#{{ x.report.run_number }}{% endif %}</a></td>
c987c865 Andy McCall ↶ 62
    <td>{{ x.report.job }}</td>
63
    <td><span class="cov-bar {{ self.class_of(x.report.percent()) }}"><span style="width: {% if let Some(p) = x.report.percent() %}{{ p }}{% else %}0{% endif %}%"></span></span> {{ self.pct(x.report.percent()) }}</td>
64
    <td class="num">{% if let Some(d) = x.delta %}<span class="cov-change {{ self.delta_class(d) }}">{{ self.signed(d) }}</span>{% endif %}</td>
65
    <td class="num">{{ x.report.lines_hit }} / {{ x.report.lines_found }}</td>
66
    <td class="small"><time title="{{ x.report.created_ms|when_i }}">{{ x.report.created_ms|ago_i }}</time></td>
67
  </tr>{% endfor %}
68
  </table></div>
69
</section>{% endif %}
70
554ccacf Andy McCall ↶ 71
<section class="panel">
72
  <h2>Files <small class="mute">sorted by {% if sort == "missed" %}lines missed{% else if sort == "percent" %}coverage, lowest first{% else %}path{% endif %}:
73
    {% if sort != "missed" %}<a href="?report={{ r.id }}&sort=missed">lines missed</a> {% endif %}{% if sort != "percent" %}<a href="?report={{ r.id }}&sort=percent">lowest first</a> {% endif %}{% if sort != "path" %}<a href="?report={{ r.id }}&sort=path">path</a>{% endif %}</small></h2>
74
  <div class="table"><table class="cov-files">
75
  <tr><th>File</th><th>Coverage</th><th class="num">Lines</th><th class="num">Missed</th></tr>
76
  {% for f in files %}<tr>
77
    <td><a href="{{ repo.url }}/coverage/{{ r.id }}/file/{{ f.path }}">{{ f.path }}</a></td>
78
    <td><span class="cov-bar {{ self.class_of(f.percent()) }}" role="img" aria-label="{{ self.pct(f.percent()) }}"><span style="width: {% if let Some(p) = f.percent() %}{{ p }}{% else %}0{% endif %}%"></span></span> {{ self.pct(f.percent()) }}</td>
79
    <td class="num">{{ f.lines_found }}</td>
80
    <td class="num">{{ f.missed() }}</td>
81
  </tr>{% endfor %}
82
  </table></div>
83
</section>
84
{% else %}
c987c865 Andy McCall ↶ 85
<div class="head"><h1>Coverage <small>of {{ bookmark }}</small></h1></div>
554ccacf Andy McCall ↶ 86
<section class="panel">
87
  <p>No coverage report for <strong>{{ bookmark }}</strong> yet.</p>
88
  <p>Give a job in <code>.flow/pipeline.kdl</code> an artifact named <code>coverage</code> holding an LCOV report, and the hub reads it when the job uploads it. For Rust:</p>
89
<pre>job "coverage" {
90
    sandbox "rust"
91
    exec "cargo" "llvm-cov" "--workspace" "--lcov" "--output-path" "/src/target/lcov.info"
92
    output {
93
        artifact "coverage" { path "/src/target/lcov.info" }
94
    }
95
}</pre>
7fff30c4 Andy McCall ↶ 96
  <p class="small mute">Istanbul (<code>--reporter=lcov</code>), coverage.py (<code>coverage lcov</code>) and gcov with lcov write LCOV too; Cobertura XML (<code>coverage xml</code>, Coverlet, JaCoCo through cover2cover) is read as well. Paths are read relative to the job's <code>/src</code>.</p>
554ccacf Andy McCall ↶ 97
</section>
98
{% endif %}
99
{% endblock %}