583 lines
14 KiB
HTML
583 lines
14 KiB
HTML
{#-
|
|
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
# You may not use this file except in compliance with the License.
|
|
# A copy of the License is located at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# or in the "license" file accompanying this file. This file 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.
|
|
-#}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>
|
|
Pipeline {{ pipe["name"] }}
|
|
</title>
|
|
<style>
|
|
#title{
|
|
background-color: #ec407a;
|
|
color: white;
|
|
padding: 2em;
|
|
}
|
|
h1 {
|
|
margin-bottom: 0em;
|
|
}
|
|
#subtitle {
|
|
font-variant: small-caps;
|
|
text-transform: lowercase;
|
|
letter-spacing: 0.2em;
|
|
}
|
|
.run-info ul {
|
|
list-style: none;
|
|
}
|
|
.run-info ul li {
|
|
display: inline;
|
|
margin-right: 6em;
|
|
margin-left: -3em;
|
|
text-transform: uppercase;
|
|
font-size: small;
|
|
color: #ec407a;
|
|
}
|
|
#content {
|
|
max-width: 800px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
padding-top: 2em;
|
|
color: #263238;
|
|
font-family: Helvetica, sans-serif;
|
|
}
|
|
p {
|
|
margin: 0;
|
|
}
|
|
.command-table {
|
|
background-color: #eceff1;
|
|
padding: 0.3em;
|
|
border-radius: 0.3em;
|
|
margin-bottom: 4em;
|
|
}
|
|
.command-table .fail-ignored {
|
|
background-color: #e65100cc;
|
|
padding: 0.3em;
|
|
border-radius: 0.3em;
|
|
}
|
|
.command-table .success {
|
|
background-color: #1a237ecc;
|
|
padding: 0.3em;
|
|
border-radius: 0.3em;
|
|
}
|
|
.command-table .in-progress {
|
|
background-color: #26323844;
|
|
padding: 0.3em;
|
|
border-radius: 0.3em;
|
|
}
|
|
.command-table .fail {
|
|
background-color: #f44336cc;
|
|
padding: 0.3em;
|
|
border-radius: 0.3em;
|
|
}
|
|
.command-content {
|
|
background-color: #eceff1;
|
|
padding: 1em;
|
|
}
|
|
.command-description {
|
|
color: #26323899;
|
|
font-size: smaller;
|
|
text-align: center;
|
|
margin-bottom: 1em;
|
|
font-weight: bold;
|
|
}
|
|
.command-invocation {
|
|
padding: 1em;
|
|
color: #fff;
|
|
background-color: #005662;
|
|
font-size: small;
|
|
font-family: monospace;
|
|
border-radius: 0.5em;
|
|
text-shadow: 0 0 2px #ffccbccc;
|
|
}
|
|
.command-stats-table {
|
|
margin-top: 0.2em;
|
|
border-radius: 0.5em;
|
|
padding: 0.2em;
|
|
padding-top: 0.4em;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #eae3998a;
|
|
color: #263238cc;
|
|
margin-bottom: 0.2em;
|
|
}
|
|
.command-stats-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-evenly;
|
|
margin-top: 0.4em;
|
|
margin-bottom: 0.4em;
|
|
font-size: small;
|
|
text-transform: uppercase;
|
|
}
|
|
.command-stats-row p .value {
|
|
color: #00251aaa;
|
|
text-shadow: 0 0 2px #82ada944;
|
|
font-weight: bold;
|
|
}
|
|
.output-box {
|
|
margin-top: 0.4em;
|
|
margin-bottom: 0.2em;
|
|
padding: 1em;
|
|
color: #000a12;
|
|
background-color: #cfd8dc;
|
|
font-size: small;
|
|
font-family: monospace;
|
|
border-radius: 0.5em;
|
|
max-height: 20em;
|
|
overflow-x: auto;
|
|
overflow-y: auto;
|
|
}
|
|
.output-box xmp{
|
|
white-space: pre;
|
|
}
|
|
.stage-name p {
|
|
margin-left: 0.5em;
|
|
color: #546e7a;
|
|
text-shadow: -1px 0px 0px #fff
|
|
,-2px 0px 0px #ffffff99
|
|
,-1px 1px 0px #ffffff99
|
|
;
|
|
font-size: 48pt;
|
|
font-variant: small-caps;
|
|
text-transform: lowercase;
|
|
font-weight: bold;
|
|
font-style: italic;
|
|
}
|
|
.stage-name .underline {
|
|
width: 100%;
|
|
height: 1.1em;
|
|
background-color: #546e7a;
|
|
margin-top: -1.6em;
|
|
}
|
|
.stage-name {
|
|
margin-top: 6em;
|
|
margin-bottom: 3em;
|
|
}
|
|
|
|
.outcome-table-info-box {
|
|
margin-top: 0.4em;
|
|
margin-bottom: 0.2em;
|
|
padding: 1em;
|
|
color: #000a12;
|
|
background-color: #ffee58;
|
|
border-radius: 0.5em;
|
|
}
|
|
.outcome-table-info-box .outcome{
|
|
font-weight: bold;
|
|
}
|
|
#toc {
|
|
margin-bottom: 6em;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-shrink: 1;
|
|
margin-right: 3em;
|
|
}
|
|
.toc-title {
|
|
text-align: center;
|
|
font-variant: small-caps;
|
|
text-transform: lowercase;
|
|
margin-bottom: -1em;
|
|
}
|
|
.toc-section{
|
|
margin-top: 1em;
|
|
margin-bottom: 0.5em;
|
|
text-transform: capitalize;
|
|
}
|
|
.toc-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
}
|
|
.toc-row-icon {
|
|
padding-right: 8px;
|
|
}
|
|
.status-icon-cross {
|
|
fill: #f44336;
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
.status-icon-tick {
|
|
fill: #3f51b5;
|
|
stroke: #ffffff77;
|
|
stroke-width: 1px;
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.status-icon-in-progress {
|
|
fill: #333;
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.status-icon-in-progress circle {
|
|
stroke: #333;
|
|
stroke-width: 2px;
|
|
fill: none
|
|
}
|
|
a:link {
|
|
color: #1e88e5;
|
|
}
|
|
a:visited {
|
|
color: #1e88e5;
|
|
}
|
|
a:visited:hover {
|
|
background-color: #1e88e5;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
}
|
|
a:hover {
|
|
background-color: #1e88e5;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
}
|
|
a:active {
|
|
background-color: #ec407a;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
}
|
|
a:visited:active {
|
|
background-color: #ec407a;
|
|
color: #fff;
|
|
text-decoration: none;
|
|
}
|
|
|
|
#contents-container {
|
|
margin-top: 6em;
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: flex-start;
|
|
align-content: flex-start;
|
|
}
|
|
|
|
#depgraph {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
align-content: flex-start;
|
|
flex-shrink: 7;
|
|
}
|
|
|
|
#depgraph-title p {
|
|
text-align: center;
|
|
font-variant: small-caps;
|
|
text-transform: lowercase;
|
|
}
|
|
|
|
#depgraph-preview img {
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
|
|
#depgraph-preview {
|
|
padding: 1em;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark){
|
|
a:link {
|
|
color: #29b6f6;
|
|
}
|
|
a:visited {
|
|
color: #29b6f6;
|
|
}
|
|
a:visited:hover {
|
|
color: #263238;
|
|
background-color: #29b6f6;
|
|
}
|
|
a:hover {
|
|
color: #263238;
|
|
background-color: #29b6f6;
|
|
}
|
|
a:active {
|
|
color: #263238;
|
|
background-color: #ec407a;
|
|
}
|
|
a:visited:active {
|
|
color: #263238;
|
|
background-color: #ec407a;
|
|
}
|
|
body {
|
|
color: #babdbe;
|
|
background-color: #263238;
|
|
}
|
|
.outcome-table-info-box p{
|
|
color: #000a12;
|
|
}
|
|
p {
|
|
color: #babdbe;
|
|
}
|
|
#subtitle {
|
|
color: #fff;
|
|
}
|
|
.command-table {
|
|
background-color: #37474f;
|
|
}
|
|
.command-content {
|
|
background-color: #37474f;
|
|
}
|
|
.command-invocation p {
|
|
color: #fff;
|
|
}
|
|
.command-stats-table {
|
|
background-color: #eae399d0;
|
|
color: #263238;
|
|
}
|
|
.command-stats-table p {
|
|
color: #263238;
|
|
}
|
|
.output-box {
|
|
color: #cfd8dccc;
|
|
background-color: #102027;
|
|
}
|
|
.stage-name p {
|
|
text-shadow: -1px 0px 0px #263238,
|
|
-2px 0px 0px #26323899,
|
|
-1px 1px 0px #26323899;
|
|
}
|
|
.status-icon-in-progress { fill: #ddd; }
|
|
.status-icon-in-progress circle { stroke: #ddd; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="content">
|
|
|
|
<div id="title">
|
|
<h1>
|
|
{{ run["project"] }} pipeline ‘{{ pipe["name"] }}’
|
|
</h1>
|
|
<p id="subtitle">
|
|
Litani CI Dashboard
|
|
</p>
|
|
</div><!-- id="title" -->
|
|
|
|
<div class=run-info>
|
|
<ul>
|
|
<li>Pipeline status: {{ pipe["status"] }}</li>
|
|
<li>{{ run["start_time"] }}</li>
|
|
<li>{{ run["run_id"] }}</li>
|
|
</ul>
|
|
</div><!-- class=run-info -->
|
|
|
|
<div id="contents-container">
|
|
|
|
<div id="toc">
|
|
<div class="toc-title">
|
|
<p>Summary of jobs for this pipeline</p>
|
|
</div><!-- class="toc-title" -->
|
|
|
|
{% for stage in pipe["ci_stages"] %}
|
|
<div class="toc-section">
|
|
<p>{{ stage["name"] }}</p>
|
|
</div><!-- class="toc-section" -->
|
|
{% for job in stage["jobs"] %}
|
|
<div class="toc-row">
|
|
|
|
<div class="toc-row-icon">
|
|
{% if job["complete"] and job["outcome"] == "success" %}
|
|
<svg height="16px" width="16px" class="status-icon-tick">
|
|
<polygon points="1,11 6,15 15,3 13,1 6,12 3,8"></polygon>
|
|
</svg>
|
|
{% elif job["complete"] %}
|
|
<svg height="16px" width="16px" class="status-icon-cross">
|
|
<polygon points="
|
|
1,3 7,8 1,13 3,15 8,9 13,15 15,13 9,8 15,3 13,1 8,7 3,1">
|
|
</polygon>
|
|
</svg>
|
|
{% else %}
|
|
<svg height="16px" width="16px" class="status-icon-in-progress">
|
|
<polygon points="7,8 8,9 9,8 8,1"> </polygon>
|
|
<polygon points="8,8 8,9 11,11 9,8"> </polygon>
|
|
<circle cx="8" cy="8" r="7"></circle>
|
|
</svg>
|
|
{% endif %}{# job["complete"] #}
|
|
</div><!-- class="toc-row-icon" -->
|
|
|
|
<div class="toc-row-job-name">
|
|
<p>
|
|
<a href="#job-{{ job['wrapper_arguments']['job_id'] }}">
|
|
{% if job["wrapper_arguments"]["description"] %}
|
|
{{ job["wrapper_arguments"]["description"] }}
|
|
{% else %}
|
|
[no description]
|
|
{% endif %}{# job["description"] #}
|
|
</a>
|
|
</p>
|
|
</div><!-- class="toc-row-job-name" -->
|
|
|
|
</div><!-- class="toc-row" -->
|
|
|
|
{% endfor %}{# job in stage["jobs"] #}
|
|
{% endfor %}{# stage in pipe["ci_stages"] #}
|
|
</div><!-- id="toc" -->
|
|
|
|
|
|
{% if "dependencies_url" in pipe %}
|
|
<div id="depgraph">
|
|
<div id="depgraph-title">
|
|
<p>Dependency graph for pipeline</p>
|
|
<p>(click for larger version)</p>
|
|
</div><!-- id="depgraph-title" -->
|
|
<a href="{{ pipe['dependencies_url'] }}">
|
|
<div id="depgraph-preview">
|
|
<img
|
|
src="{{ pipe['dependencies_url'] }}"
|
|
alt="pipeline dependency graph" />
|
|
</div><!-- id="depgraph-preview" -->
|
|
</a><!-- href="{{ dependencies_url }}" -->
|
|
</div><!-- id="depgraph" -->
|
|
{% endif %}{# "depgraph_preview" in job #}
|
|
|
|
</div><!-- id="contents-container" -->
|
|
|
|
|
|
{% for stage in pipe["ci_stages"] %}
|
|
<div class="stage">
|
|
<div class="stage-name">
|
|
<p>{{ stage["name"] }}</p>
|
|
<div class="underline"></div>
|
|
</div><!-- class="stage-name" -->
|
|
|
|
{% for job in stage["jobs"] %}
|
|
<div class="command-table" id="job-{{ job['wrapper_arguments']['job_id'] }}">
|
|
{% if not job["complete"] %}
|
|
<div class="in-progress">
|
|
{% elif job["outcome"] == "success" %}
|
|
<div class="success">
|
|
{% else %}
|
|
<div class="fail">
|
|
{% endif %}{# not job["complete"] #}
|
|
<div class="command-content">
|
|
<div class="command-description">
|
|
{% if "description" in job["wrapper_arguments"] %}
|
|
<p>
|
|
{{ job["wrapper_arguments"]["description"] }}
|
|
</p>
|
|
{% endif %}{# "description" in job #}
|
|
</div><!-- class="command-description" -->
|
|
<div class="command-invocation">
|
|
<p>
|
|
{{ job["wrapper_arguments"]["command"] }}
|
|
</p>
|
|
</div><!-- class="command-invocation" -->
|
|
|
|
{% if job["complete"] %}
|
|
<div class="command-stats-table">
|
|
<div class="command-stats-row">
|
|
<p>Command return code:
|
|
<span class="value">
|
|
{{ job["command_return_code"] }}
|
|
</span></p>
|
|
<p>OK returns:
|
|
<span class="value">
|
|
{{ job["wrapper_arguments"]["ok_returns"] }}
|
|
</span></p>
|
|
<p>Ignored returns:
|
|
<span class="value">
|
|
{{ job["wrapper_arguments"]["ignore_returns"] }}
|
|
</span></p>
|
|
</div><!-- class="command-stats-row" -->
|
|
<div class="command-stats-row">
|
|
<p>Timeout:
|
|
<span class="value">
|
|
{{ job["wrapper_arguments"]["timeout"] }}
|
|
</span></p>
|
|
<p>Timeout ok:
|
|
<span class="value">
|
|
{{ job["wrapper_arguments"]["timeout_ok"] }}
|
|
</span></p>
|
|
<p>Timeout ignored:
|
|
<span class="value">
|
|
{{ job["wrapper_arguments"]["timeout_ignore"] }}
|
|
</span></p>
|
|
<p>Timeout reached:
|
|
<span class="value">
|
|
{{ job["timeout_reached"] }}
|
|
</span></p>
|
|
</div><!-- class="command-stats-row" -->
|
|
<div class="command-stats-row">
|
|
<p>Start time:
|
|
<span class="value">
|
|
{{ job["start_time"] }}
|
|
</span></p>
|
|
<p>Duration:
|
|
<span class="value">
|
|
{{ job["duration_str"] }}
|
|
</span></p>
|
|
<p>End time:
|
|
<span class="value">
|
|
{{ job["end_time"] }}
|
|
</span></p>
|
|
</div><!-- class="command-stats-row" -->
|
|
<div class="command-stats-row">
|
|
<p>Command successful:
|
|
<span class="value">
|
|
{% if job["outcome"] == "success" %}
|
|
yes
|
|
{% else %}
|
|
no
|
|
{% endif %}{# job["outcome"] == "success"#}
|
|
</span></p>
|
|
</div><!-- class="command-stats-row" -->
|
|
</div><!-- class="command-stats-table" -->
|
|
{% endif %}{# job["complete"] #}
|
|
|
|
{% if job["complete"] and job["loaded_outcome_dict"] %}
|
|
<div class="outcome-table-info-box">
|
|
<p>
|
|
An outcome table decided the outcome
|
|
‘<span class="outcome">{{ job["outcome"] }}</span>’
|
|
for this job. View the table
|
|
<a href="{{ job['outcome_table_html_url'] }}">here</a>
|
|
(or view the
|
|
<a href="{{ job['outcome_table_json_url'] }}">raw JSON</a>).
|
|
</p>
|
|
</div><!-- class="outcome-table-info-box" -->
|
|
{% endif %}{# job["loaded_outcome_dict"] #}
|
|
|
|
|
|
{% if job["stdout"] %}
|
|
<div class="output-box"><xmp>stdout:
|
|
{% for line in job["stdout"] %}
|
|
{{ line.strip() }}
|
|
{%- endfor %}{# line in job["stdout"] #}
|
|
</xmp>
|
|
</div><!-- class="output-box" -->
|
|
{% endif %}{# job["stdout"] #}
|
|
|
|
{% if job["stderr"] %}
|
|
<div class="output-box"><xmp>stderr:
|
|
{% for line in job["stderr"] %}
|
|
{{ line.strip() }}
|
|
{%- endfor %}{# line in job["stderr"] #}
|
|
</xmp>
|
|
</div><!-- class="output-box" -->
|
|
{% endif %}{# job["stderr"] #}
|
|
|
|
</div><!-- class="command-content" -->
|
|
</div><!-- class="fail" -->
|
|
</div><!-- id="command-table" -->
|
|
{% endfor %}{# command in stage["jobs"] #}
|
|
|
|
</div><!-- class="stage" -->
|
|
{% endfor %}{# stage in pipe["ci_stages"] #}
|
|
|
|
|
|
</div><!-- id="content" -->
|
|
</body>
|
|
</html>
|