added stage details to dashboard

pull/1/head
Brad Rydzewski 5 years ago
parent 9d455b9e23
commit f581e81ec4

@ -9,6 +9,7 @@ package handler
import (
"net/http"
"sort"
"strconv"
"github.com/drone/drone-go/drone"
hook "github.com/drone/runner-go/logger/history"
@ -48,12 +49,33 @@ func HandleIndex(t *history.History) http.HandlerFunc {
}
}
// HandleStage returns a http.HandlerFunc that displays the
// stage details.
func HandleStage(t *history.History) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
d := t.Entries()
s := r.FormValue("id")
id, _ := strconv.ParseInt(s, 10, 64)
for _, e := range t.Entries() {
if e.Stage.ID == id {
nocache(w)
render(w, "stage.tmpl", d)
return
}
}
// TODO(bradrydzewski) we need an error template.
w.WriteHeader(404)
}
}
// HandleLogHistory returns a http.HandlerFunc that displays a
// list recent log entries.
func HandleLogHistory(t *hook.Hook) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
nocache(w)
render(w, "logs.tmpl", t.Entries())
render(w, "logs.tmpl", struct {
Entries []*hook.Entry
}{t.Entries()})
}
}
@ -63,11 +85,6 @@ type data struct {
Items []*history.Entry
}
// helper function returns true if the history is empty.
func (d *data) Empty() bool {
return len(d.Items) == 0
}
// helper function returns true if no running builds exists.
func (d *data) Idle() bool {
for _, item := range d.Items {

@ -36,6 +36,7 @@ func New(tracer *history.History, history *hook.Hook, config Config) http.Handle
mux.Handle("/static/", http.StripPrefix("/static/", fs))
mux.HandleFunc("/healthz", handler.HandleHealth(tracer))
mux.Handle("/logs", auth(handler.HandleLogHistory(history)))
mux.Handle("/stage", auth(handler.HandleStage(tracer)))
mux.Handle("/", auth(handler.HandleIndex(tracer)))
return mux
}

@ -79,6 +79,10 @@ header .logo {
margin-bottom: 10px;
}
a.card {
text-decoration: none;
}
/*
* stage card component
*/
@ -149,6 +153,69 @@ header .logo {
margin-left: 9px;
}
/*
* step components
*/
.steps header {
border-bottom: 1px solid rgba(30,55,90,.1);
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
padding: 10px 15px;
}
.steps header .name {
align-items: center;
display: flex;
font-weight: 600;
}
.steps .step {
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
padding: 10px 15px;
}
.steps .step:hover {
background: #f8f8fa;
}
.steps .step .name {
align-items: center;
display: flex;
}
.steps .body {
padding: 10px 0px;
}
.steps .status {
position: relative;
}
.steps .step .status:before,
.steps .step .status:after {
border-left: 1px solid #1e375a;
content: " ";
height: 10px;
left: 50%;
opacity: 0.15;
position: absolute;
top: 20px;
width: 1px;
}
.steps .step .status:before {
top: -10px;
}
.steps .step:last-of-type .status:after,
.steps .step:first-of-type .status:before {
display: none;
}
/**
* alert components
*/

@ -220,8 +220,8 @@ var files = map[string]file{
data: file10,
FileInfo: &fileInfo{
name: "style.css",
size: 6669,
modTime: time.Unix(1563049338, 0),
size: 7701,
modTime: time.Unix(1563073228, 0),
},
},
"/timeago.js": {
@ -1199,6 +1199,10 @@ header .logo {
margin-bottom: 10px;
}
a.card {
text-decoration: none;
}
/*
* stage card component
*/
@ -1269,6 +1273,69 @@ header .logo {
margin-left: 9px;
}
/*
* step components
*/
.steps header {
border-bottom: 1px solid rgba(30,55,90,.1);
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
padding: 10px 15px;
}
.steps header .name {
align-items: center;
display: flex;
font-weight: 600;
}
.steps .step {
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
padding: 10px 15px;
}
.steps .step:hover {
background: #f8f8fa;
}
.steps .step .name {
align-items: center;
display: flex;
}
.steps .body {
padding: 10px 0px;
}
.steps .status {
position: relative;
}
.steps .step .status:before,
.steps .step .status:after {
border-left: 1px solid #1e375a;
content: " ";
height: 10px;
left: 50%;
opacity: 0.15;
position: absolute;
top: 20px;
width: 1px;
}
.steps .step .status:before {
top: -10px;
}
.steps .step:last-of-type .status:after,
.steps .step:first-of-type .status:before {
display: none;
}
/**
* alert components
*/

@ -29,7 +29,7 @@
<h1>Dashboard</h1>
</header>
<article class="cards stages">
{{ if .Empty }}
{{ if not .Items }}
<div class="alert sleeping">
<p>There is no recent activity to display.</p>
</div>
@ -39,14 +39,14 @@
</div>
{{ end }}
{{ range .Items }}
<div class="card stage">
<a href="/stage/{{ .ID }}" class="card stage">
<h2>{{ .Repo.Slug }}</h2>
<img src="{{ .Build.AuthorAvatar }}" />
<span class="connector"></span>
<span class="status {{ .Stage.Status }}"></span>
<span class="desc">assigned stage <em>{{ .Stage.Name }}</em> for build <em>#{{ .Build.Number }}</em></span>
<span class="time" datetime="{{ if .Stage.Started }}{{ timestamp .Stage.Started }}{{ else }}{{ timestamp .Stage.Created }}{{ end }}"></span>
</div>
</a>
{{ end }}
</article>
</section>

@ -27,9 +27,9 @@
<header>
<h1>Recent Logs</h1>
</header>
{{ if . }}
{{ if .Entries }}
<article class="logs">
{{ range . }}
{{ range .Entries }}
<div class="entry">
<span class="level {{ .Level }}">{{ .Level }}</span>
<span class="message">{{ .Message }}</span>
@ -38,7 +38,7 @@
<span><em>{{ $key }}</em>{{ $val }}</span>
{{ end }}
</span>
<span class="time" datetime="{{ timestamp .Time.Unix }}"></span>
<span class="time" datetime="{{ timestamp .Unix }}"></span>
</div>
{{ end }}
</article>

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Dashboard</title>
<link rel="stylesheet" type="text/css" href="/static/reset.css">
<link rel="stylesheet" type="text/css" href="/static/style.css">
<link rel="icon" type="image/png" id="favicon" href="/static/favicon.png">
<script src="/static/timeago.js" type="text/javascript"></script>
</head>
<body>
<header class="navbar">
<div class="logo">
<svg viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M12.086 5.814l-.257.258 10.514 10.514C20.856 18.906 20 21.757 20 25c0 9.014 6.618 15 15 15 3.132 0 6.018-.836 8.404-2.353l10.568 10.568C48.497 55.447 39.796 60 30 60 13.434 60 0 46.978 0 30 0 19.903 4.751 11.206 12.086 5.814zm5.002-2.97C20.998 1.015 25.378 0 30 0c16.566 0 30 13.022 30 30 0 4.67-1.016 9.04-2.835 12.923l-9.508-9.509C49.144 31.094 50 28.243 50 25c0-9.014-6.618-15-15-15-3.132 0-6.018.836-8.404 2.353l-9.508-9.508zM35 34c-5.03 0-9-3.591-9-9s3.97-9 9-9c5.03 0 9 3.591 9 9s-3.97 9-9 9z" id="a"></path></defs><use fill="#FFF" xlink:href="#a" fill-rule="evenodd"></use></svg>
</div>
<nav class="inline-nav">
<ul>
<li><a href="/">Dashboard</a></li>
<li><a href="/logs">Logging</a></li>
</ul>
</nav>
</header>
<main>
<section>
<header>
<h1>{{ .Repo.Slug }}</h1>
</header>
<div class="card stage">
<h2>{{ .Build.Message }}</h2>
<img src="{{ .Build.AuthorAvatar }}" />
<span class="connector"></span>
<span class="status {{ .Stage.Status }}"></span>
{{ if eq .Build.Event "pull_request" }}
{{ if eq .Build.Action "synchronized" }}
<span class="desc">{{ .Build.Author }} synchronized pull request <em>#{{ pr .Build.Ref }}</em></span>
{{ else }}
<span class="desc">{{ .Build.Author }} opened pull request <em>#{{ pr .Build.Ref }}</em> to <em>{{ .Build.Target }}</em></span>
{{ end }}
{{ else if eq .Build.Event "tag" }}
<span class="desc">{{ .Build.Author }} created reference <em>{{ tag .Build.Ref }}</em></span>
{{ else if eq .Build.Event "promote"}}
<span class="desc">{{ .Build.Author }} promoted build <em>#{{ .Build.Parent }}</em> to <em>{{ .Build.Deploy }}</em></span>
{{ else }}
<span class="desc">{{ .Build.Author }} pushed <em>{{ sha .Build.After }}</em> to <em>{{ .Build.Target }}</em></span>
{{ end }}
<span class="time" datetime="{{ if .Stage.Started }}{{ timestamp .Stage.Started }}{{ else }}{{ timestamp .Stage.Created }}{{ end }}"></span>
</div>
{{ if .Stage.Steps }}
<div class="card steps">
<header>
<span class="status {{ .Stage.Status }}"></span>
<span class="name">{{ .Stage.Name }}</span>
</header>
<div class="body">
{{ range .Stage.Steps }}
<div class="step">
<span class="status {{ .Status }}"></span>
<span class="name"> {{ .Name }}</span>
</div>
{{ end }}
</div>
</div>
{{ end }}
</section>
</main>
<footer></footer>
<script>
timeago.render(document.querySelectorAll('.time'));
</script>
</body>
</html>

@ -0,0 +1,106 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Parity Public License
// that can be found in the LICENSE file.
// +build ignore
package main
import (
"encoding/json"
"html/template"
"io/ioutil"
"log"
"net/http"
"path/filepath"
"regexp"
"strings"
"time"
)
func main() {
addr := ":3333"
// serve templates with dummy data
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
path := r.FormValue("data")
if path == "" {
http.Error(w, "missing data parameter", 500)
return
}
tmpl := r.FormValue("template")
if path == "" {
http.Error(w, "missing template parameter", 500)
return
}
// read the json data from file.
rawjson, err := ioutil.ReadFile(filepath.Join("testdata", path))
if err != nil {
http.Error(w, "cannot open json file", 500)
return
}
// unmarshal the json data
data := map[string]interface{}{}
err = json.Unmarshal(rawjson, &data)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// load the templates
T := template.New("_").Funcs(funcMap)
matches, _ := filepath.Glob("files/*.tmpl")
for _, match := range matches {
raw, _ := ioutil.ReadFile(match)
base := filepath.Base(match)
T = template.Must(
T.New(base).Parse(string(raw)),
)
}
// render the template
w.Header().Set("Content-Type", "text/html")
err = T.ExecuteTemplate(w, tmpl, data)
if err != nil {
log.Println(err)
}
})
// serve static content.
http.Handle("/static/",
http.StripPrefix("/static/",
http.FileServer(
http.Dir("../static/files"),
),
),
)
log.Printf("listening at %s", addr)
log.Fatalln(http.ListenAndServe(addr, nil))
}
// regular expression to extract the pull request number
// from the git ref (e.g. refs/pulls/{d}/head)
var re = regexp.MustCompile("\\d+")
// mirros the func map in template.go
var funcMap = map[string]interface{}{
"timestamp": func(v float64) string {
return time.Unix(int64(v), 0).UTC().Format("2006-01-02T15:04:05Z")
},
"pr": func(s string) string {
return re.FindString(s)
},
"sha": func(s string) string {
if len(s) > 8 {
s = s[:8]
}
return s
},
"tag": func(s string) string {
return strings.TrimPrefix(s, "refs/tags/")
},
}

@ -5,13 +5,32 @@
package template
import (
"regexp"
"strings"
"time"
)
//go:generate togo tmpl -func funcMap -format html
// regular expression to extract the pull request number
// from the git ref (e.g. refs/pulls/{d}/head)
var re = regexp.MustCompile("\\d+")
// mirros the func map in template.go
var funcMap = map[string]interface{}{
"timestamp": func(v int64) string {
return time.Unix(v, 0).UTC().Format("2006-01-02T15:04:05Z")
"timestamp": func(v float64) string {
return time.Unix(int64(v), 0).UTC().Format("2006-01-02T15:04:05Z")
},
"pr": func(s string) string {
return re.FindString(s)
},
"sha": func(s string) string {
if len(s) > 8 {
s = s[:8]
}
return s
},
"tag": func(s string) string {
return strings.TrimPrefix(s, "refs/tags/")
},
}

@ -13,6 +13,9 @@ var files = []struct {
}, {
name: "logs.tmpl",
data: logs,
}, {
name: "stage.tmpl",
data: stage,
},
}
@ -64,7 +67,7 @@ var index = `<!DOCTYPE html>
<h1>Dashboard</h1>
</header>
<article class="cards stages">
{{ if .Empty }}
{{ if not .Items }}
<div class="alert sleeping">
<p>There is no recent activity to display.</p>
</div>
@ -74,14 +77,14 @@ var index = `<!DOCTYPE html>
</div>
{{ end }}
{{ range .Items }}
<div class="card stage">
<a href="/stage/{{ .ID }}" class="card stage">
<h2>{{ .Repo.Slug }}</h2>
<img src="{{ .Build.AuthorAvatar }}" />
<span class="connector"></span>
<span class="status {{ .Stage.Status }}"></span>
<span class="desc">assigned stage <em>{{ .Stage.Name }}</em> for build <em>#{{ .Build.Number }}</em></span>
<span class="time" datetime="{{ if .Stage.Started }}{{ timestamp .Stage.Started }}{{ else }}{{ timestamp .Stage.Created }}{{ end }}"></span>
</div>
</a>
{{ end }}
</article>
</section>
@ -125,9 +128,9 @@ var logs = `<!DOCTYPE html>
<header>
<h1>Recent Logs</h1>
</header>
{{ if . }}
{{ if .Entries }}
<article class="logs">
{{ range . }}
{{ range .Entries }}
<div class="entry">
<span class="level {{ .Level }}">{{ .Level }}</span>
<span class="message">{{ .Message }}</span>
@ -136,7 +139,7 @@ var logs = `<!DOCTYPE html>
<span><em>{{ $key }}</em>{{ $val }}</span>
{{ end }}
</span>
<span class="time" datetime="{{ timestamp .Time.Unix }}"></span>
<span class="time" datetime="{{ timestamp .Unix }}"></span>
</div>
{{ end }}
</article>
@ -155,3 +158,82 @@ timeago.render(document.querySelectorAll('.time'));
</script>
</body>
</html>`
// files/stage.tmpl
var stage = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Dashboard</title>
<link rel="stylesheet" type="text/css" href="/static/reset.css">
<link rel="stylesheet" type="text/css" href="/static/style.css">
<link rel="icon" type="image/png" id="favicon" href="/static/favicon.png">
<script src="/static/timeago.js" type="text/javascript"></script>
</head>
<body>
<header class="navbar">
<div class="logo">
<svg viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M12.086 5.814l-.257.258 10.514 10.514C20.856 18.906 20 21.757 20 25c0 9.014 6.618 15 15 15 3.132 0 6.018-.836 8.404-2.353l10.568 10.568C48.497 55.447 39.796 60 30 60 13.434 60 0 46.978 0 30 0 19.903 4.751 11.206 12.086 5.814zm5.002-2.97C20.998 1.015 25.378 0 30 0c16.566 0 30 13.022 30 30 0 4.67-1.016 9.04-2.835 12.923l-9.508-9.509C49.144 31.094 50 28.243 50 25c0-9.014-6.618-15-15-15-3.132 0-6.018.836-8.404 2.353l-9.508-9.508zM35 34c-5.03 0-9-3.591-9-9s3.97-9 9-9c5.03 0 9 3.591 9 9s-3.97 9-9 9z" id="a"></path></defs><use fill="#FFF" xlink:href="#a" fill-rule="evenodd"></use></svg>
</div>
<nav class="inline-nav">
<ul>
<li><a href="/">Dashboard</a></li>
<li><a href="/logs">Logging</a></li>
</ul>
</nav>
</header>
<main>
<section>
<header>
<h1>{{ .Repo.Slug }}</h1>
</header>
<div class="card stage">
<h2>{{ .Build.Message }}</h2>
<img src="{{ .Build.AuthorAvatar }}" />
<span class="connector"></span>
<span class="status {{ .Stage.Status }}"></span>
{{ if eq .Build.Event "pull_request" }}
{{ if eq .Build.Action "synchronized" }}
<span class="desc">{{ .Build.Author }} synchronized pull request <em>#{{ pr .Build.Ref }}</em></span>
{{ else }}
<span class="desc">{{ .Build.Author }} opened pull request <em>#{{ pr .Build.Ref }}</em> to <em>{{ .Build.Target }}</em></span>
{{ end }}
{{ else if eq .Build.Event "tag" }}
<span class="desc">{{ .Build.Author }} created reference <em>{{ tag .Build.Ref }}</em></span>
{{ else if eq .Build.Event "promote"}}
<span class="desc">{{ .Build.Author }} promoted build <em>#{{ .Build.Parent }}</em> to <em>{{ .Build.Deploy }}</em></span>
{{ else }}
<span class="desc">{{ .Build.Author }} pushed <em>{{ sha .Build.After }}</em> to <em>{{ .Build.Target }}</em></span>
{{ end }}
<span class="time" datetime="{{ if .Stage.Started }}{{ timestamp .Stage.Started }}{{ else }}{{ timestamp .Stage.Created }}{{ end }}"></span>
</div>
{{ if .Stage.Steps }}
<div class="card steps">
<header>
<span class="status {{ .Stage.Status }}"></span>
<span class="name">{{ .Stage.Name }}</span>
</header>
<div class="body">
{{ range .Stage.Steps }}
<div class="step">
<span class="status {{ .Status }}"></span>
<span class="name"> {{ .Name }}</span>
</div>
{{ end }}
</div>
</div>
{{ end }}
</section>
</main>
<footer></footer>
<script>
timeago.render(document.querySelectorAll('.time'));
</script>
</body>
</html>`

@ -0,0 +1,34 @@
{
"Entries": [
{
"Level": "trace",
"Message": "this is a test trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "this is a test debug message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "info",
"Message": "this is an info trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058975
},
{
"Level": "warn",
"Message": "this is a test warning message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058977
},
{
"Level": "error",
"Message": "this is a test error message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563059000
}
]
}

@ -0,0 +1,3 @@
{
"Entries": []
}

@ -0,0 +1,59 @@
{
"Logs": [
{
"Level": "trace",
"Message": "this is a test trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "this is a test debug message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "info",
"Message": "this is an info trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058975
},
{
"Level": "warn",
"Message": "this is a test warning message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058977
},
{
"Level": "error",
"Message": "this is a test error message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563059000
}
],
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"After": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
"Event": "push",
"Source": "master",
"Target": "master",
"Message": "Merge pull request #6 from Spaceghost/patch-1",
"Author": "octocat",
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "success",
"Started": 1563059000,
"Created": 1563059000,
"Steps": [
{ "Name": "clone", "Status": "success" },
{ "Name": "build", "Status": "success" },
{ "Name": "test", "Status": "success" },
{ "Name": "deploy", "Status": "success" }
]
}
}

@ -0,0 +1,61 @@
{
"Logs": [
{
"Level": "trace",
"Message": "this is a test trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "this is a test debug message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "info",
"Message": "this is an info trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058975
},
{
"Level": "warn",
"Message": "this is a test warning message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058977
},
{
"Level": "error",
"Message": "this is a test error message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563059000
}
],
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"After": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
"Event": "promote",
"Source": "master",
"Target": "master",
"Deploy": "production",
"Message": "Merge pull request #6 from Spaceghost/patch-1",
"Author": "octocat",
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Parent": 41,
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "success",
"Started": 1563059000,
"Created": 1563059000,
"Steps": [
{ "Name": "clone", "Status": "success" },
{ "Name": "build", "Status": "success" },
{ "Name": "test", "Status": "success" },
{ "Name": "deploy", "Status": "success" }
]
}
}

@ -0,0 +1,29 @@
{
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"Ref": "refs/pull/42/head",
"After": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
"Event": "pull_request",
"Action": "opened",
"Source": "master",
"Target": "master",
"Message": "Merge pull request #6 from Spaceghost/patch-1",
"Author": "octocat",
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "success",
"Started": 1563059000,
"Created": 1563059000,
"Steps": [
{ "Name": "clone", "Status": "success" },
{ "Name": "build", "Status": "success" },
{ "Name": "test", "Status": "success" },
{ "Name": "deploy", "Status": "success" }
]
}
}

@ -0,0 +1,60 @@
{
"Logs": [
{
"Level": "trace",
"Message": "this is a test trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "this is a test debug message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058875
},
{
"Level": "info",
"Message": "this is an info trace message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058975
},
{
"Level": "warn",
"Message": "this is a test warning message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563058977
},
{
"Level": "error",
"Message": "this is a test error message",
"Data": { "foo": "bar", "baz": "boo" },
"Unix": 1563059000
}
],
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"After": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
"Event": "tag",
"Source": "master",
"Target": "master",
"Ref": "refs/tags/v1.0.0",
"Message": "Merge pull request #6 from Spaceghost/patch-1",
"Author": "octocat",
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "success",
"Started": 1563059000,
"Created": 1563059000,
"Steps": [
{ "Name": "clone", "Status": "success" },
{ "Name": "build", "Status": "success" },
{ "Name": "test", "Status": "success" },
{ "Name": "deploy", "Status": "success" }
]
}
}

@ -0,0 +1,21 @@
{
"Items": [
{
"ID": 1,
"Idle": false,
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "running",
"Started": 1563059000,
"Created": 1563059000
}
}
]
}

@ -0,0 +1,4 @@
{
"Idle": true,
"Items": []
}

@ -0,0 +1,20 @@
{
"Idle": true,
"Items": [
{
"Repo": {
"Slug": "octocat/hello-world"
},
"Build": {
"AuthorAvatar": "https://avatars0.githubusercontent.com/u/583231?s=460&v=4",
"Number": 42
},
"Stage": {
"Name": "test",
"Status": "success",
"Started": 1563059000,
"Created": 1563059000
}
}
]
}

@ -8,7 +8,6 @@ package history
// to log recent log activity.
import (
"sync"
"time"
"github.com/sirupsen/logrus"
)
@ -33,7 +32,7 @@ type Entry struct {
Level Level
Message string
Data map[string]interface{}
Time time.Time
Unix int64
}
// Hook is a logrus hook that track the log history.
@ -63,7 +62,7 @@ func (h *Hook) Fire(e *logrus.Entry) error {
h.entries = append(h.entries, &Entry{
Level: convertLevel(e.Level),
Data: convertFields(e.Data),
Time: e.Time,
Unix: e.Time.Unix(),
Message: e.Message,
})
h.Unlock()

@ -93,13 +93,13 @@ func TestHistory(t *testing.T) {
Level: LevelDebug,
Message: "foo",
Data: logrus.Fields{"foo": "bar"},
Time: now,
Unix: now.Unix(),
},
{
Level: LevelInfo,
Message: "bar",
Data: logrus.Fields{"baz": "qux"},
Time: now,
Unix: now.Unix(),
},
}
if diff := cmp.Diff(entries, expect); diff != "" {

Loading…
Cancel
Save