github.com/yrj2011/jx-test-infra@v0.0.0-20190529031832-7a2065ee98eb/prow/cmd/deck/badge.go (about) 1 /* 2 Copyright 2018 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 package main 18 19 import ( 20 "bytes" 21 "html/template" 22 23 "path/filepath" 24 "sort" 25 "strings" 26 27 "k8s.io/test-infra/prow/kube" 28 ) 29 30 var svg = `<svg xmlns="http://www.w3.org/2000/svg" width="{{.Width}}" height="20"> 31 <linearGradient id="a" x2="0" y2="100%"> 32 <stop offset="0" stop-color="#bbb" stop-opacity=".1"/> 33 <stop offset="1" stop-opacity=".1"/> 34 </linearGradient> 35 <rect rx="3" width="100%" height="20" fill="#555"/> 36 <g fill="{{.Color}}"> 37 <rect rx="3" x="{{.RightStart}}" width="{{.RightWidth}}" height="20"/> 38 <path d="M{{.RightStart}} 0h4v20h-4z"/> 39 </g> 40 <rect rx="3" width="100%" height="20" fill="url(#a)"/> 41 <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> 42 <g fill="#010101" opacity=".3"> 43 <text x="{{.XposLeft}}" y="15">{{.Subject}}</text> 44 <text x="{{.XposRight}}" y="15">{{.Status}}</text> 45 </g> 46 <text x="{{.XposLeft}}" y="14">{{.Subject}}</text> 47 <text x="{{.XposRight}}" y="14">{{.Status}}</text> 48 </g> 49 </svg>` 50 51 var svgTemplate = template.Must(template.New("svg").Parse(svg)) 52 53 // Make a small SVG badge that looks like `[subject | status]`, with the status 54 // text in the given color. Provides a local version of the shields.io service. 55 func makeShield(subject, status, color string) []byte { 56 // TODO(rmmh): Use better font-size metrics for prettier badges-- estimating 57 // character widths as 6px isn't very accurate. 58 // See also: https://github.com/badges/shields/blob/master/measure-text.js 59 p := struct { 60 Width, RightStart, RightWidth int 61 XposLeft, XposRight float64 62 Subject, Status string 63 Color string 64 }{ 65 Subject: subject, 66 Status: status, 67 RightStart: 13 + 6*len(subject), 68 RightWidth: 13 + 6*len(status), 69 } 70 p.Width = p.RightStart + p.RightWidth 71 p.XposLeft = float64(p.RightStart) * 0.5 72 p.XposRight = float64(p.RightStart) + float64(p.RightWidth-2)*0.5 73 switch color { 74 case "brightgreen": 75 p.Color = "#4c1" 76 case "red": 77 p.Color = "#e05d44" 78 default: 79 p.Color = color 80 } 81 var buf bytes.Buffer 82 svgTemplate.Execute(&buf, p) 83 return buf.Bytes() 84 } 85 86 // pickLatestJobs returns the most recent run of each job matching the selector, 87 // which is comma-separated list of globs, for example "ci-ti-*,ci-other". 88 func pickLatestJobs(jobs []kube.ProwJob, selector string) []kube.ProwJob { 89 var out []kube.ProwJob 90 have := make(map[string]bool) 91 want := strings.Split(selector, ",") 92 for _, job := range jobs { 93 if have[job.Spec.Job] { 94 continue // already have the latest result for this job 95 } 96 for _, pat := range want { 97 if match, _ := filepath.Match(pat, job.Spec.Job); match { 98 have[job.Spec.Job] = true 99 out = append(out, job) 100 break 101 } 102 } 103 } 104 return out 105 } 106 107 func renderBadge(jobs []kube.ProwJob) (string, string, []byte) { 108 color := "brightgreen" 109 status := "passing" 110 if len(jobs) == 0 { 111 color = "darkgrey" 112 status = "no results" 113 } else { 114 failedJobs := []string{} 115 for _, job := range jobs { 116 if job.Status.State == "failure" { 117 failedJobs = append(failedJobs, job.Spec.Job) 118 } 119 } 120 sort.Strings(failedJobs) 121 if len(failedJobs) > 3 { 122 failedJobs = append(failedJobs[:3], "...") 123 } 124 if len(failedJobs) > 0 { 125 color = "red" 126 status = "failing " + strings.Join(failedJobs, ", ") 127 } 128 } 129 130 return status, color, makeShield("build", status, color) 131 }