Skip to content

Commit

Permalink
Add CSV and HTML reports to buildruns command
Browse files Browse the repository at this point in the history
Add the same report options to the buildruns command.

Refactor code to avoid duplication.
  • Loading branch information
HeavyWombat committed Dec 1, 2020
1 parent a27732e commit a6bb9a8
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 127 deletions.
25 changes: 6 additions & 19 deletions internal/cmd/buildrun-series.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ limitations under the License.
package cmd

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/gonvenience/bunt"
"github.com/gonvenience/wrap"
Expand Down Expand Up @@ -76,23 +73,13 @@ var buildRunSeriesCmd = &cobra.Command{
return err
}

var store = func(filename string, f func(w io.Writer) error) error {
var buf bytes.Buffer
f(&buf)
return ioutil.WriteFile(filename, buf.Bytes(), os.FileMode(0644))
}

if len(buildRunSeriesCmdSettings.htmlOutput) > 0 {
store(buildRunSeriesCmdSettings.htmlOutput, func(w io.Writer) error {
return load.CreateChartJS(results, w)
})
}
store(buildRunSeriesCmdSettings.htmlOutput, func(w io.Writer) error {
return load.CreateChartJS(results, w)
})

if len(buildRunSeriesCmdSettings.csvOutput) > 0 {
store(buildRunSeriesCmdSettings.csvOutput, func(w io.Writer) error {
return load.CreateBuildRunResultSetCSV(results, w)
})
}
store(buildRunSeriesCmdSettings.csvOutput, func(w io.Writer) error {
return load.CreateBuildRunResultSetCSV(results, w)
})

return nil
},
Expand Down
15 changes: 15 additions & 0 deletions internal/cmd/buildrun-single.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package cmd

import (
"fmt"
"io"

"github.com/gonvenience/bunt"
"github.com/homeport/build-load/internal/load"
Expand All @@ -28,6 +29,9 @@ var buildRunOnceCmdSettings struct {
parallel int
namingCfg load.NamingConfig
buildCfg load.BuildConfig

htmlOutput string
csvOutput string
}

var buildRunOnceCmd = &cobra.Command{
Expand All @@ -51,6 +55,14 @@ var buildRunOnceCmd = &cobra.Command{
return err
}

store(buildRunOnceCmdSettings.htmlOutput, func(w io.Writer) error {
return load.CreateBuildrunResultsChartJS(buildRunResults, w)
})

store(buildRunOnceCmdSettings.csvOutput, func(w io.Writer) error {
return load.CreateBuildRunResultsCSV(buildRunResults, w)
})

fmt.Print(load.CalculateBuildRunResultSet(buildRunResults))

return nil
Expand All @@ -65,6 +77,9 @@ func init() {

buildRunOnceCmd.Flags().IntVar(&buildRunOnceCmdSettings.parallel, "parallel", 1, "number of parallel buildruns")

buildRunOnceCmd.Flags().StringVar(&buildRunOnceCmdSettings.htmlOutput, "html", "", "filename of the HTML report")
buildRunOnceCmd.Flags().StringVar(&buildRunOnceCmdSettings.csvOutput, "csv", "", "filename of the CSV report")

applyNamingFlags(buildRunOnceCmd, &buildRunOnceCmdSettings.namingCfg)
applyBuildRunSettingsFlags(buildRunOnceCmd, &buildRunOnceCmdSettings.buildCfg)
}
14 changes: 14 additions & 0 deletions internal/cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ limitations under the License.
package cmd

import (
"bytes"
"io"
"io/ioutil"
"os"
"time"

"github.com/gonvenience/bunt"
Expand Down Expand Up @@ -82,3 +86,13 @@ func applyBuildRunSettingsFlags(cmd *cobra.Command, buildCfg *load.BuildConfig)
cobra.MarkFlagRequired(pf, "source-url")
cobra.MarkFlagRequired(pf, "output-image-url")
}

func store(filename string, f func(w io.Writer) error) error {
if len(filename) == 0 {
return nil
}

var buf bytes.Buffer
f(&buf)
return ioutil.WriteFile(filename, buf.Bytes(), os.FileMode(0644))
}
252 changes: 144 additions & 108 deletions internal/load/reports_chartjs.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,119 +20,157 @@ import (
"fmt"
"html/template"
"io"
"strconv"
)

// CreateChartJS creates a page with ChartsJS to render the provided results
func CreateChartJS(data []BuildRunResultSet, w io.Writer) error {
const reportTemplate = `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
</head>
<body>
<div class="chart-container" style="position: relative; width:90vw;">
<canvas id="myChart"></canvas>
</div>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: {{ .Labels }},
datasets: {{ .Datasets }},
},
options: {
title: {
display: true,
text: 'Build run times with different numbers of parallel builds'
},
tooltips: {
displayColors: true,
callbacks: {
mode: 'x',
},
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'number of parallel builds'
},
gridLines: {
display: false,
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'time in seconds'
},
ticks: {
beginAtZero: true,
},
type: 'linear',
}]
},
responsive: true,
maintainAspectRatio: true,
legend: { position: 'bottom' },
}
});
</script>
</body>
</html>
`
const reportTemplate = `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
</head>
<body>
<div class="chart-container" style="position: relative; width:90vw;">
<canvas id="myChart"></canvas>
</div>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: {{ .Labels }},
datasets: {{ .Datasets }},
},
options: {
title: {
display: true,
text: {{ .Text }}
},
tooltips: {
displayColors: true,
callbacks: {
mode: 'x',
},
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: {{ .LabelX }}
},
gridLines: {
display: false,
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: {{ .LabelY }}
},
ticks: {
beginAtZero: true,
},
type: 'linear',
}]
},
responsive: true,
maintainAspectRatio: true,
legend: { position: 'bottom' },
}
});
</script>
</body>
</html>
`

type dataset struct {
Label string `json:"label"`
BackgroundColor string `json:"backgroundColor"`
Data []float64 `json:"data"`
}

type inputs struct {
Text string
LabelX string
LabelY string
Labels []string
Datasets []dataset
}

func prepareDatasets() []dataset {
return []dataset{
{
Label: BuildrunCompletionTime,
BackgroundColor: "#6cf9a6",
Data: []float64{},
},
{
Label: BuildrunControlTime,
BackgroundColor: "#fdc10a",
Data: []float64{},
},
{
Label: TaskrunCompletionTime,
BackgroundColor: "#34a887",
Data: []float64{},
},
{
Label: TaskrunControlTime,
BackgroundColor: "#ad36a6",
Data: []float64{},
},
{
Label: PodCompletionTime,
BackgroundColor: "#a064a6",
Data: []float64{},
},
{
Label: PodControlTime,
BackgroundColor: "#ada469",
Data: []float64{},
},
}
}

// CreateBuildrunResultsChartJS creates a page with ChartJS to display the results of buildruns
func CreateBuildrunResultsChartJS(data []BuildRunResult, w io.Writer) error {
tmpl, err := template.New("report").Parse(reportTemplate)
if err != nil {
return err
}

type dataset struct {
Label string `json:"label"`
BackgroundColor string `json:"backgroundColor"`
Data []float64 `json:"data"`
}
var labels = []string{}
var datasets = prepareDatasets()

var (
labels = []string{}
datasets = []dataset{
{
Label: BuildrunCompletionTime,
BackgroundColor: "#6cf9a6",
Data: []float64{},
},
{
Label: BuildrunControlTime,
BackgroundColor: "#fdc10a",
Data: []float64{},
},
{
Label: TaskrunCompletionTime,
BackgroundColor: "#34a887",
Data: []float64{},
},
{
Label: TaskrunControlTime,
BackgroundColor: "#ad36a6",
Data: []float64{},
},
{
Label: PodCompletionTime,
BackgroundColor: "#a064a6",
Data: []float64{},
},
{
Label: PodControlTime,
BackgroundColor: "#ada469",
Data: []float64{},
},
for i, buildRunResult := range data {
labels = append(labels, strconv.Itoa(i+1))

for j, value := range buildRunResult {
datasets[j].Data = append(datasets[j].Data, value.Value.Seconds())
}
)
}

return tmpl.Execute(w, inputs{
Text: "BuildRun times",
LabelX: "buildrun",
LabelY: "time in seconds",
Labels: labels,
Datasets: datasets,
})
}

// CreateChartJS creates a page with ChartsJS to render the provided results
func CreateChartJS(data []BuildRunResultSet, w io.Writer) error {
tmpl, err := template.New("report").Parse(reportTemplate)
if err != nil {
return err
}

var labels = []string{}
var datasets = prepareDatasets()

for _, buildRunResultSet := range data {
labels = append(labels, fmt.Sprintf("%d", buildRunResultSet.NumberOfResults))
Expand All @@ -145,12 +183,10 @@ func CreateChartJS(data []BuildRunResultSet, w io.Writer) error {
datasets[5].Data = append(datasets[5].Data, buildRunResultSet.Median.ValueOf(PodControlTime).Seconds())
}

type inputs struct {
Labels []string
Datasets []dataset
}

return tmpl.Execute(w, inputs{
Text: "Build run times with different numbers of parallel builds",
LabelX: "number of parallel builds",
LabelY: "time in seconds",
Labels: labels,
Datasets: datasets,
})
Expand Down
Loading

0 comments on commit a6bb9a8

Please sign in to comment.