chiark / gitweb /
site: build status page.
authorVladimír Vondruš <mosra@centrum.cz>
Thu, 18 Jan 2018 12:11:17 +0000 (13:11 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Thu, 18 Jan 2018 12:11:17 +0000 (13:11 +0100)
Basically stolen from Magnum.

doc/build-status.js [new file with mode: 0644]
doc/build-status.rst [new file with mode: 0644]
site/pelicanconf.py

diff --git a/doc/build-status.js b/doc/build-status.js
new file mode 100644 (file)
index 0000000..f92da95
--- /dev/null
@@ -0,0 +1,124 @@
+var projects = [['mosra/m.css', 'master']];
+var latestTravisJobs = [];
+var travisDone = 0;
+var travisJobIdRe = /JOBID=([a-zA-Z0-9-]+)/
+
+/* Ability to override the projects via query string */
+if(location.search) {
+    let params = new URLSearchParams(location.search);
+    projects = []
+    for(let p of params) projects.push(p);
+}
+
+function timeDiff(before, now) {
+    var diff = now.getTime() - before.getTime();
+
+    /* Try days first. If less than two days, try hours. If less than two
+       hours, try minutes. If less than a minute, say "now". */
+    if(diff/(24*60*60*1000) > 2)
+        return Math.round(diff/(24*60*60*1000)) + "d ago";
+    else if(diff/(60*60*1000) > 2)
+        return Math.round(diff/(60*60*1000)) + "h ago";
+    else if(diff/(60*1000) > 1)
+        return Math.round(diff/(60*1000)) + "m ago";
+    else
+        return "now";
+}
+
+function fetchTravisJobStatus(latestJobs) {
+    var req = window.XDomainRequest ? new XDomainRequest() : new XMLHttpRequest();
+    if(!req) return;
+
+    req.open("GET", 'https://api.travis-ci.org/jobs?ids[]=' + latestJobs.join('&ids[]='), true);
+    req.setRequestHeader("Accept", "application/vnd.travis-ci.2+json");
+    req.responseType = 'json';
+    req.onreadystatechange = function() {
+        if(req.readyState != 4) return;
+
+        //console.log(req.response);
+
+        var now = new Date(Date.now());
+        var jobs = req.response['jobs'];
+        for(var i = 0; i != jobs.length; ++i) {
+            var match = jobs[i]['config']['env'].match(travisJobIdRe);
+            if(!match) continue;
+
+            /* ID is combined repository name (w/o author) and the job ID from
+               environment */
+            var repo = jobs[i]['repository_slug'];
+            var id = repo.substr(repo.indexOf('/') + 1).replace("m.css", "mcss") + "-" + match[1];
+            var elem = document.getElementById(id);
+            if(!elem) {
+                console.log('Unknown Travis job ID', id);
+                continue;
+            }
+
+            var type;
+            var status;
+            var ageField;
+            if(jobs[i]['state'] == 'passed') {
+                type = 'm-success';
+                status = '✔';
+                ageField = 'finished_at';
+            } else if(jobs[i]['state'] == 'started') {
+                type = 'm-warning';
+                status = '↺';
+                ageField = 'started_at';
+            } else if(jobs[i]['state'] == 'canceled') {
+                type = 'm-dim';
+                status = '∅';
+                ageField = 'finished_at';
+            } else if(jobs[i]['state'] == 'received' ||
+                      jobs[i]['state'] == 'created' ||
+                      jobs[i]['state'] == 'queued') {
+                type = 'm-info';
+                status = '…';
+                ageField = '';
+            } else if(jobs[i]['state'] == 'errored' ||
+                      jobs[i]['state'] == 'failed') {
+                type = 'm-danger';
+                status = '✘';
+                ageField = 'finished_at';
+            } else {
+                type = 'm-default';
+                status = jobs[i]['state'];
+                ageField = 'started_at';
+            }
+
+            var age;
+            var title;
+            if(ageField) {
+                age = timeDiff(new Date(Date.parse(jobs[i][ageField])), now);
+                title = jobs[i]['state'] + ' @ ' + jobs[i][ageField];
+            } else {
+                age = '';
+                title = jobs[i]['state'];
+            }
+
+            elem.innerHTML = '<a href="https://travis-ci.org/' + repo + '/jobs/' + jobs[i]['id'] + '" title="' + title + '">' + status + '<br /><span class="m-text m-small">' + age + '</span></a>';
+            elem.className = type;
+        }
+    };
+    req.send();
+}
+
+function fetchLatestTravisJobs(project, branch) {
+    var req = window.XDomainRequest ? new XDomainRequest() : new XMLHttpRequest();
+    if(!req) return;
+
+    req.open("GET", 'https://api.travis-ci.org/repos/' + project + '/branches/' + branch, true);
+    req.setRequestHeader("Accept", "application/vnd.travis-ci.2+json");
+    req.responseType = 'json';
+    req.onreadystatechange = function() {
+        if(req.readyState != 4) return;
+
+        latestTravisJobs = latestTravisJobs.concat(req.response['branch']['job_ids']);
+        if(++travisDone == projects.length)
+            fetchTravisJobStatus(latestTravisJobs);
+    };
+    req.send();
+}
+
+for(var i = 0; i != projects.length; ++i) {
+    fetchLatestTravisJobs(projects[i][0], projects[i][1]);
+}
diff --git a/doc/build-status.rst b/doc/build-status.rst
new file mode 100644 (file)
index 0000000..52fade7
--- /dev/null
@@ -0,0 +1,79 @@
+Build Status
+############
+
+:summary: CI build status of m.css
+:footer:
+    .. raw:: html
+
+        <style>
+          table.build-status th, table.build-status td {
+            text-align: center;
+            vertical-align: middle;
+          }
+          table.build-status td.m-success,
+          table.build-status td.m-warning,
+          table.build-status td.m-danger,
+          table.build-status td.m-info,
+          table.build-status td.m-dim {
+            padding: 0;
+          }
+          table.build-status a {
+            display: block;
+            width: 100%;
+            height: 100%;
+            padding: 0.25rem 0.5rem;
+            text-decoration: none;
+          }
+        </style>
+        <script>
+
+    .. raw:: html
+        :file: build-status.js
+
+    .. raw:: html
+
+        </script>
+
+Show builds for:
+
+-   `master branch <{filename}/build-status.rst>`_
+-   `next branch <{filename}/build-status.rst?mosra/m.css=next>`_
+
+.. container:: m-container-inflate
+
+    .. container:: m-scroll
+
+        .. raw:: html
+
+            <table class="m-table build-status">
+              <thead>
+                <tr>
+                  <th></th>
+                  <th>Python<br />3.4</th>
+                  <th>Python<br />3.5</th>
+                  <th>Python<br />3.6</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <th class="m-text-right">Pelican theme</th>
+                  <td rowspan="2" id="mcss-py34"></td>
+                  <td rowspan="2" id="mcss-py35"></td>
+                  <td rowspan="3" id="mcss-py36"></td>
+                </tr>
+                <tr>
+                  <th class="m-text-right">Pelican plugins</th>
+                </tr>
+                <tr>
+                  <th class="m-text-right">Doxygen theme</th>
+                  <td class="m-dim"></td>
+                  <td class="m-dim"></td>
+                </tr>
+                <tr>
+                  <th class="m-text-right">Math rendering</th>
+                  <td class="m-dim"></td>
+                  <td class="m-dim"></td>
+                  <td class="m-dim"></td>
+                </tr>
+              </tbody>
+            </table>
index 7b043ce3ae4b0dfefa362bede4d65a059c7e96c0..120dce4c048d49c47485fd5c80e4242dd1d8ecef 100644 (file)
@@ -94,7 +94,8 @@ M_LINKS_FOOTER1 = [('m.css', '/'),
                    ('GitHub', 'https://github.com/mosra/m.css'),
                    ('Gitter', 'https://gitter.im/mosra/m.css'),
                    ('E-mail', 'mailto:mosra@centrum.cz'),
-                   ('Twitter', 'https://twitter.com/czmosra')]
+                   ('Twitter', 'https://twitter.com/czmosra'),
+                   ('Build Status', 'build-status/')]
 
 M_LINKS_FOOTER2 = [('CSS', 'css/'),
                    ('Grid system', 'css/grid/'),