mirror of
https://github.com/drone/drone-cli.git
synced 2024-11-23 09:21:56 +01:00
added inject and matrix packages
This commit is contained in:
parent
3c15f21133
commit
211c90ed4a
54
compiler/inject/inject.go
Normal file
54
compiler/inject/inject.go
Normal file
@ -0,0 +1,54 @@
|
||||
package inject
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone-cli/common"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Inject injects a map of parameters into a raw string and returns
|
||||
// the resulting string.
|
||||
//
|
||||
// Parameters are represented in the string using $$ notation, similar
|
||||
// to how environment variables are defined in Makefiles.
|
||||
func Inject(raw string, params map[string]string) string {
|
||||
if params == nil {
|
||||
return raw
|
||||
}
|
||||
keys := []string{}
|
||||
for k := range params {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
||||
injected := raw
|
||||
for _, k := range keys {
|
||||
v := params[k]
|
||||
injected = strings.Replace(injected, "$$"+k, v, -1)
|
||||
}
|
||||
return injected
|
||||
}
|
||||
|
||||
// InjectSafe attempts to safely inject parameters without leaking
|
||||
// parameters in the Build or Compose section of the yaml file.
|
||||
//
|
||||
// The intended use case for this function are public pull requests.
|
||||
// We want to avoid a malicious pull request that allows someone
|
||||
// to inject and print private variables.
|
||||
func InjectSafe(raw string, params map[string]string) string {
|
||||
before, _ := parse(raw)
|
||||
after, _ := parse(Inject(raw, params))
|
||||
before.Notify = after.Notify
|
||||
before.Publish = after.Publish
|
||||
before.Deploy = after.Deploy
|
||||
result, _ := yaml.Marshal(before)
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// helper funtion to parse a yaml configuration file.
|
||||
func parse(raw string) (*common.Config, error) {
|
||||
cfg := common.Config{}
|
||||
err := yaml.Unmarshal([]byte(raw), &cfg)
|
||||
return &cfg, err
|
||||
}
|
67
compiler/inject/inject_test.go
Normal file
67
compiler/inject/inject_test.go
Normal file
@ -0,0 +1,67 @@
|
||||
package inject
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/franela/goblin"
|
||||
)
|
||||
|
||||
func Test_Inject(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Inject params", func() {
|
||||
|
||||
g.It("Should replace vars with $$", func() {
|
||||
s := "echo $$FOO $BAR"
|
||||
m := map[string]string{}
|
||||
m["FOO"] = "BAZ"
|
||||
g.Assert("echo BAZ $BAR").Equal(Inject(s, m))
|
||||
})
|
||||
|
||||
g.It("Should not replace vars with single $", func() {
|
||||
s := "echo $FOO $BAR"
|
||||
m := map[string]string{}
|
||||
m["FOO"] = "BAZ"
|
||||
g.Assert(s).Equal(Inject(s, m))
|
||||
})
|
||||
|
||||
g.It("Should not replace vars in nil map", func() {
|
||||
s := "echo $$FOO $BAR"
|
||||
g.Assert(s).Equal(Inject(s, nil))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_InjectSafe(t *testing.T) {
|
||||
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Safely Inject params", func() {
|
||||
|
||||
m := map[string]string{}
|
||||
m["TOKEN"] = "FOO"
|
||||
m["SECRET"] = "BAR"
|
||||
c, _ := parse(InjectSafe(yml, m))
|
||||
|
||||
g.It("Should replace vars in notify section", func() {
|
||||
g.Assert(c.Deploy["digital_ocean"].Config["token"]).Equal("FOO")
|
||||
g.Assert(c.Deploy["digital_ocean"].Config["secret"]).Equal("BAR")
|
||||
})
|
||||
|
||||
g.It("Should not replace vars in script section", func() {
|
||||
g.Assert(c.Build.Config["commands"].([]interface{})[0]).Equal("echo $$TOKEN")
|
||||
g.Assert(c.Build.Config["commands"].([]interface{})[1]).Equal("echo $$SECRET")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var yml = `
|
||||
build:
|
||||
image: foo
|
||||
commands:
|
||||
- echo $$TOKEN
|
||||
- echo $$SECRET
|
||||
deploy:
|
||||
digital_ocean:
|
||||
token: $$TOKEN
|
||||
secret: $$SECRET
|
||||
`
|
@ -1,4 +1,4 @@
|
||||
package matrix
|
||||
package parser
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@ -18,9 +18,8 @@ type Matrix map[string][]string
|
||||
// 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.
|
||||
// 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 {
|
||||
@ -31,12 +30,8 @@ func (a Axis) String() string {
|
||||
|
||||
// Parse parses the Matrix section of the yaml file and
|
||||
// returns a list of axis.
|
||||
//
|
||||
// Note that this method will cap the result set to
|
||||
// avoid caclulating permutations on too large of a
|
||||
// dataset and consuming too many system resources.
|
||||
func Parse(raw string) ([]Axis, error) {
|
||||
matrix, err := parse(raw)
|
||||
matrix, err := parseMatrix(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -47,6 +42,14 @@ func Parse(raw string) ([]Axis, error) {
|
||||
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)
|
||||
@ -75,7 +78,7 @@ func Parse(raw string) ([]Axis, error) {
|
||||
elem := p / decr % len(elems)
|
||||
axis[tag] = elems[elem]
|
||||
|
||||
// enforce a maximum number of rows
|
||||
// enforce a maximum number of tags
|
||||
// in the build matrix.
|
||||
if i > limitTags {
|
||||
break
|
||||
@ -92,12 +95,12 @@ func Parse(raw string) ([]Axis, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return axisList, nil
|
||||
return axisList
|
||||
}
|
||||
|
||||
// helper function to parse the Matrix data from
|
||||
// the raw yaml file.
|
||||
func parse(raw string) (Matrix, error) {
|
||||
func parseMatrix(raw string) (Matrix, error) {
|
||||
data := struct {
|
||||
Matrix map[string][]string
|
||||
}{}
|
||||
|
@ -1,45 +1,33 @@
|
||||
package matrix
|
||||
package parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/franela/goblin"
|
||||
)
|
||||
|
||||
func Test_Parse(t *testing.T) {
|
||||
axis, err := Parse(matrix)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
func Test_Matrix(t *testing.T) {
|
||||
|
||||
if len(axis) != 24 {
|
||||
t.Errorf("Expected 24 axis, got %d", len(axis))
|
||||
}
|
||||
g := goblin.Goblin(t)
|
||||
g.Describe("Calculate matrix", func() {
|
||||
|
||||
unique := map[string]bool{}
|
||||
for _, a := range axis {
|
||||
unique[a.String()] = true
|
||||
}
|
||||
m := map[string][]string{}
|
||||
m["go_version"] = []string{"go1", "go1.2"}
|
||||
m["python_version"] = []string{"3.2", "3.3"}
|
||||
m["django_version"] = []string{"1.7", "1.7.1", "1.7.2"}
|
||||
m["redis_version"] = []string{"2.6", "2.8"}
|
||||
axis := Calc(m)
|
||||
|
||||
if len(unique) != 24 {
|
||||
t.Errorf("Expected 24 unique permutations in matrix, got %d", len(unique))
|
||||
}
|
||||
g.It("Should calculate permutations", func() {
|
||||
g.Assert(len(axis)).Equal(24)
|
||||
})
|
||||
|
||||
g.It("Should not duplicate permutations", func() {
|
||||
set := map[string]bool{}
|
||||
for _, perm := range axis {
|
||||
set[perm.String()] = true
|
||||
}
|
||||
g.Assert(len(set)).Equal(24)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var matrix = `
|
||||
build:
|
||||
image: $$python_version $$redis_version $$django_version $$go_version
|
||||
matrix:
|
||||
python_version:
|
||||
- 3.2
|
||||
- 3.3
|
||||
redis_version:
|
||||
- 2.6
|
||||
- 2.8
|
||||
django_version:
|
||||
- 1.7
|
||||
- 1.7.1
|
||||
- 1.7.2
|
||||
go_version:
|
||||
- go1
|
||||
- go1.2
|
||||
`
|
||||
|
Loading…
Reference in New Issue
Block a user