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  }