workflow,lexicons: allow setting per-step env vars #246

merged
opened by anirudh.fi targeting master from push-pmtpswykplzr
Changed files
+275 -65
api
cmd
lexicons
workflow
+219 -2
api/tangled/cbor_gen.go
···
return nil
-
func (t *Pipeline_Step) MarshalCBOR(w io.Writer) error {
+
func (t *Pipeline_Step_Environment_Elem) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
···
return err
+
// t.Key (string) (string)
+
if len("key") > 1000000 {
+
return xerrors.Errorf("Value in field \"key\" was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("key"))); err != nil {
+
return err
+
}
+
if _, err := cw.WriteString(string("key")); err != nil {
+
return err
+
}
+
+
if len(t.Key) > 1000000 {
+
return xerrors.Errorf("Value in field t.Key was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil {
+
return err
+
}
+
if _, err := cw.WriteString(string(t.Key)); err != nil {
+
return err
+
}
+
+
// t.Value (string) (string)
+
if len("value") > 1000000 {
+
return xerrors.Errorf("Value in field \"value\" was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("value"))); err != nil {
+
return err
+
}
+
if _, err := cw.WriteString(string("value")); err != nil {
+
return err
+
}
+
+
if len(t.Value) > 1000000 {
+
return xerrors.Errorf("Value in field t.Value was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Value))); err != nil {
+
return err
+
}
+
if _, err := cw.WriteString(string(t.Value)); err != nil {
+
return err
+
}
+
return nil
+
}
+
+
func (t *Pipeline_Step_Environment_Elem) UnmarshalCBOR(r io.Reader) (err error) {
+
*t = Pipeline_Step_Environment_Elem{}
+
+
cr := cbg.NewCborReader(r)
+
+
maj, extra, err := cr.ReadHeader()
+
if err != nil {
+
return err
+
}
+
defer func() {
+
if err == io.EOF {
+
err = io.ErrUnexpectedEOF
+
}
+
}()
+
+
if maj != cbg.MajMap {
+
return fmt.Errorf("cbor input should be of type map")
+
}
+
+
if extra > cbg.MaxLength {
+
return fmt.Errorf("Pipeline_Step_Environment_Elem: map struct too large (%d)", extra)
+
}
+
+
n := extra
+
+
nameBuf := make([]byte, 5)
+
for i := uint64(0); i < n; i++ {
+
nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000)
+
if err != nil {
+
return err
+
}
+
+
if !ok {
+
// Field doesn't exist on this type, so ignore it
+
if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil {
+
return err
+
}
+
continue
+
}
+
+
switch string(nameBuf[:nameLen]) {
+
// t.Key (string) (string)
+
case "key":
+
+
{
+
sval, err := cbg.ReadStringWithMax(cr, 1000000)
+
if err != nil {
+
return err
+
}
+
+
t.Key = string(sval)
+
}
+
// t.Value (string) (string)
+
case "value":
+
+
{
+
sval, err := cbg.ReadStringWithMax(cr, 1000000)
+
if err != nil {
+
return err
+
}
+
+
t.Value = string(sval)
+
}
+
+
default:
+
// Field doesn't exist on this type, so ignore it
+
if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil {
+
return err
+
}
+
}
+
}
+
+
return nil
+
}
+
func (t *Pipeline_Step) MarshalCBOR(w io.Writer) error {
+
if t == nil {
+
_, err := w.Write(cbg.CborNull)
+
return err
+
}
+
+
cw := cbg.NewCborWriter(w)
+
fieldCount := 3
+
+
if t.Environment == nil {
+
fieldCount--
+
}
+
+
if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil {
+
return err
+
}
+
// t.Name (string) (string)
if len("name") > 1000000 {
return xerrors.Errorf("Value in field \"name\" was too long")
···
if _, err := cw.WriteString(string(t.Command)); err != nil {
return err
+
+
// t.Environment ([]*tangled.Pipeline_Step_Environment_Elem) (slice)
+
if t.Environment != nil {
+
+
if len("environment") > 1000000 {
+
return xerrors.Errorf("Value in field \"environment\" was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("environment"))); err != nil {
+
return err
+
}
+
if _, err := cw.WriteString(string("environment")); err != nil {
+
return err
+
}
+
+
if len(t.Environment) > 8192 {
+
return xerrors.Errorf("Slice value in field t.Environment was too long")
+
}
+
+
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Environment))); err != nil {
+
return err
+
}
+
for _, v := range t.Environment {
+
if err := v.MarshalCBOR(cw); err != nil {
+
return err
+
}
+
+
}
+
}
return nil
···
n := extra
-
nameBuf := make([]byte, 7)
+
nameBuf := make([]byte, 11)
for i := uint64(0); i < n; i++ {
nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000)
if err != nil {
···
t.Command = string(sval)
+
// t.Environment ([]*tangled.Pipeline_Step_Environment_Elem) (slice)
+
case "environment":
+
+
maj, extra, err = cr.ReadHeader()
+
if err != nil {
+
return err
+
}
+
+
if extra > 8192 {
+
return fmt.Errorf("t.Environment: array too large (%d)", extra)
+
}
+
+
if maj != cbg.MajArray {
+
return fmt.Errorf("expected cbor array")
+
}
+
+
if extra > 0 {
+
t.Environment = make([]*Pipeline_Step_Environment_Elem, extra)
+
}
+
+
for i := 0; i < int(extra); i++ {
+
{
+
var maj byte
+
var extra uint64
+
var err error
+
_ = maj
+
_ = extra
+
_ = err
+
+
{
+
+
b, err := cr.ReadByte()
+
if err != nil {
+
return err
+
}
+
if b != cbg.CborNull[0] {
+
if err := cr.UnreadByte(); err != nil {
+
return err
+
}
+
t.Environment[i] = new(Pipeline_Step_Environment_Elem)
+
if err := t.Environment[i].UnmarshalCBOR(cr); err != nil {
+
return xerrors.Errorf("unmarshaling t.Environment[i] pointer: %w", err)
+
}
+
}
+
+
}
+
+
}
+
}
default:
// Field doesn't exist on this type, so ignore it
+9 -3
api/tangled/tangledpipeline.go
···
// Pipeline_Step is a "step" in the sh.tangled.pipeline schema.
type Pipeline_Step struct {
-
Command string `json:"command" cborgen:"command"`
-
Name string `json:"name" cborgen:"name"`
+
Command string `json:"command" cborgen:"command"`
+
Environment []*Pipeline_Step_Environment_Elem `json:"environment,omitempty" cborgen:"environment,omitempty"`
+
Name string `json:"name" cborgen:"name"`
+
}
+
+
type Pipeline_Step_Environment_Elem struct {
+
Key string `json:"key" cborgen:"key"`
+
Value string `json:"value" cborgen:"value"`
}
// Pipeline_TriggerMetadata is a "triggerMetadata" in the sh.tangled.pipeline schema.
···
// Pipeline_Workflow is a "workflow" in the sh.tangled.pipeline schema.
type Pipeline_Workflow struct {
Clone *Pipeline_CloneOpts `json:"clone" cborgen:"clone"`
-
Dependencies []Pipeline_Dependencies_Elem `json:"dependencies" cborgen:"dependencies"`
+
Dependencies []Pipeline_Dependencies_Elem `json:"dependencies" cborgen:"dependencies"`
Environment []*Pipeline_Workflow_Environment_Elem `json:"environment" cborgen:"environment"`
Name string `json:"name" cborgen:"name"`
Steps []*Pipeline_Step `json:"steps" cborgen:"steps"`
+1
cmd/gen.go
···
tangled.Pipeline_ManualTriggerData{},
tangled.Pipeline_PullRequestTriggerData{},
tangled.Pipeline_PushTriggerData{},
+
tangled.Pipeline_Step_Environment_Elem{},
tangled.Pipeline_Step{},
tangled.Pipeline_TriggerMetadata{},
tangled.Pipeline_TriggerRepo{},
+27 -58
lexicons/pipeline.json
···
"key": "tid",
"record": {
"type": "object",
-
"required": [
-
"triggerMetadata",
-
"workflows"
-
],
+
"required": ["triggerMetadata", "workflows"],
"properties": {
"triggerMetadata": {
"type": "ref",
···
},
"triggerMetadata": {
"type": "object",
-
"required": [
-
"kind",
-
"repo"
-
],
+
"required": ["kind", "repo"],
"properties": {
"kind": {
"type": "string",
-
"enum": [
-
"push",
-
"pull_request",
-
"manual"
-
]
+
"enum": ["push", "pull_request", "manual"]
},
"repo": {
"type": "ref",
···
},
"triggerRepo": {
"type": "object",
-
"required": [
-
"knot",
-
"did",
-
"repo",
-
"defaultBranch"
-
],
+
"required": ["knot", "did", "repo", "defaultBranch"],
"properties": {
"knot": {
"type": "string"
···
},
"pushTriggerData": {
"type": "object",
-
"required": [
-
"ref",
-
"newSha",
-
"oldSha"
-
],
+
"required": ["ref", "newSha", "oldSha"],
"properties": {
"ref": {
"type": "string"
···
},
"pullRequestTriggerData": {
"type": "object",
-
"required": [
-
"sourceBranch",
-
"targetBranch",
-
"sourceSha",
-
"action"
-
],
+
"required": ["sourceBranch", "targetBranch", "sourceSha", "action"],
"properties": {
"sourceBranch": {
"type": "string"
···
"type": "array",
"items": {
"type": "object",
-
"required": [
-
"key",
-
"value"
-
],
+
"required": ["key", "value"],
"properties": {
"key": {
"type": "string"
···
},
"workflow": {
"type": "object",
-
"required": [
-
"name",
-
"dependencies",
-
"steps",
-
"environment",
-
"clone"
-
],
+
"required": ["name", "dependencies", "steps", "environment", "clone"],
"properties": {
"name": {
"type": "string"
···
"type": "array",
"items": {
"type": "object",
-
"required": [
-
"key",
-
"value"
-
],
+
"required": ["key", "value"],
"properties": {
"key": {
"type": "string"
···
"type": "array",
"items": {
"type": "object",
-
"required": [
-
"registry",
-
"packages"
-
],
+
"required": ["registry", "packages"],
"properties": {
"registry": {
"type": "string"
···
},
"cloneOpts": {
"type": "object",
-
"required": [
-
"skip",
-
"depth",
-
"submodules"
-
],
+
"required": ["skip", "depth", "submodules"],
"properties": {
"skip": {
"type": "boolean"
···
},
"step": {
"type": "object",
-
"required": [
-
"name",
-
"command"
-
],
+
"required": ["name", "command"],
"properties": {
"name": {
"type": "string"
},
"command": {
"type": "string"
+
},
+
"environment": {
+
"type": "array",
+
"items": {
+
"type": "object",
+
"required": ["key", "value"],
+
"properties": {
+
"key": {
+
"type": "string"
+
},
+
"value": {
+
"type": "string"
+
}
+
}
+
}
}
}
}
+7
workflow/compile.go
···
Command: s.Command,
Name: s.Name,
}
+
for k, v := range s.Environment {
+
e := &tangled.Pipeline_Step_Environment_Elem{
+
Key: k,
+
Value: v,
+
}
+
step.Environment = append(step.Environment, e)
+
}
cw.Steps = append(cw.Steps, &step)
}
for k, v := range w.Environment {
+3 -2
workflow/def.go
···
}
Step struct {
-
Name string `yaml:"name"`
-
Command string `yaml:"command"`
+
Name string `yaml:"name"`
+
Command string `yaml:"command"`
+
Environment map[string]string `yaml:"environment"`
}
StringList []string
+9
workflow/def_test.go
···
environment:
HOME: /home/foo bar/baz
CGO_ENABLED: 1
+
+
steps:
+
- name: Something
+
command: echo "hello"
+
environment:
+
FOO: bar
+
BAZ: qux
`
wf, err := FromFile("test.yml", []byte(yamlData))
···
assert.Len(t, wf.Environment, 2)
assert.Equal(t, "/home/foo bar/baz", wf.Environment["HOME"])
assert.Equal(t, "1", wf.Environment["CGO_ENABLED"])
+
assert.Equal(t, "bar", wf.Steps[0].Environment["FOO"])
+
assert.Equal(t, "qux", wf.Steps[0].Environment["BAZ"])
}