woodpecker/parser/matrix/matrix.go

109 lines
2.2 KiB
Go

package matrix
import (
"strings"
"gopkg.in/yaml.v2"
)
const (
limitTags = 10
limitAxis = 25
)
// Matrix represents the build matrix.
type Matrix map[string][]string
// Axis represents a single permutation of entries
// from the build matrix.
type Axis map[string]string
// String returns a string representation of an Axis as
// a comma-separated list of environment variables.
func (a Axis) String() string {
var envs []string
for k, v := range a {
envs = append(envs, k+"="+v)
}
return strings.Join(envs, " ")
}
// Parse parses the Matrix section of the yaml file and
// returns a list of axis.
func Parse(raw string) ([]Axis, error) {
matrix, err := parseMatrix(raw)
if err != nil {
return nil, err
}
// if not a matrix build return an array
// with just the single axis.
if len(matrix) == 0 {
return nil, nil
}
return Calc(matrix), nil
}
// Calc calculates the permutations for th build matrix.
//
// Note that this method will cap the number of permutations
// to 25 to prevent an overly expensive calculation.
func Calc(matrix Matrix) []Axis {
// calculate number of permutations and
// extract the list of tags
// (ie go_version, redis_version, etc)
var perm int
var tags []string
for k, v := range matrix {
perm *= len(v)
if perm == 0 {
perm = len(v)
}
tags = append(tags, k)
}
// structure to hold the transformed
// result set
axisList := []Axis{}
// for each axis calculate the uniqe
// set of values that should be used.
for p := 0; p < perm; p++ {
axis := map[string]string{}
decr := perm
for i, tag := range tags {
elems := matrix[tag]
decr = decr / len(elems)
elem := p / decr % len(elems)
axis[tag] = elems[elem]
// enforce a maximum number of tags
// in the build matrix.
if i > limitTags {
break
}
}
// append to the list of axis.
axisList = append(axisList, axis)
// enforce a maximum number of axis
// that should be calculated.
if p > limitAxis {
break
}
}
return axisList
}
// helper function to parse the Matrix data from
// the raw yaml file.
func parseMatrix(raw string) (Matrix, error) {
data := struct {
Matrix map[string][]string
}{}
err := yaml.Unmarshal([]byte(raw), &data)
return data.Matrix, err
}