Monorepo for Tangled tangled.org

workflow,lexicons: allow setting per-step env vars

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.sh>

authored by anirudh.fi and committed by Tangled 4904ddc6 99577302

Changed files
+275 -65
api
cmd
lexicons
workflow
+219 -2
api/tangled/cbor_gen.go
··· 3169 3169 3170 3170 return nil 3171 3171 } 3172 + func (t *Pipeline_Step_Environment_Elem) MarshalCBOR(w io.Writer) error { 3173 + if t == nil { 3174 + _, err := w.Write(cbg.CborNull) 3175 + return err 3176 + } 3177 + 3178 + cw := cbg.NewCborWriter(w) 3179 + 3180 + if _, err := cw.Write([]byte{162}); err != nil { 3181 + return err 3182 + } 3183 + 3184 + // t.Key (string) (string) 3185 + if len("key") > 1000000 { 3186 + return xerrors.Errorf("Value in field \"key\" was too long") 3187 + } 3188 + 3189 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("key"))); err != nil { 3190 + return err 3191 + } 3192 + if _, err := cw.WriteString(string("key")); err != nil { 3193 + return err 3194 + } 3195 + 3196 + if len(t.Key) > 1000000 { 3197 + return xerrors.Errorf("Value in field t.Key was too long") 3198 + } 3199 + 3200 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil { 3201 + return err 3202 + } 3203 + if _, err := cw.WriteString(string(t.Key)); err != nil { 3204 + return err 3205 + } 3206 + 3207 + // t.Value (string) (string) 3208 + if len("value") > 1000000 { 3209 + return xerrors.Errorf("Value in field \"value\" was too long") 3210 + } 3211 + 3212 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("value"))); err != nil { 3213 + return err 3214 + } 3215 + if _, err := cw.WriteString(string("value")); err != nil { 3216 + return err 3217 + } 3218 + 3219 + if len(t.Value) > 1000000 { 3220 + return xerrors.Errorf("Value in field t.Value was too long") 3221 + } 3222 + 3223 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Value))); err != nil { 3224 + return err 3225 + } 3226 + if _, err := cw.WriteString(string(t.Value)); err != nil { 3227 + return err 3228 + } 3229 + return nil 3230 + } 3231 + 3232 + func (t *Pipeline_Step_Environment_Elem) UnmarshalCBOR(r io.Reader) (err error) { 3233 + *t = Pipeline_Step_Environment_Elem{} 3234 + 3235 + cr := cbg.NewCborReader(r) 3236 + 3237 + maj, extra, err := cr.ReadHeader() 3238 + if err != nil { 3239 + return err 3240 + } 3241 + defer func() { 3242 + if err == io.EOF { 3243 + err = io.ErrUnexpectedEOF 3244 + } 3245 + }() 3246 + 3247 + if maj != cbg.MajMap { 3248 + return fmt.Errorf("cbor input should be of type map") 3249 + } 3250 + 3251 + if extra > cbg.MaxLength { 3252 + return fmt.Errorf("Pipeline_Step_Environment_Elem: map struct too large (%d)", extra) 3253 + } 3254 + 3255 + n := extra 3256 + 3257 + nameBuf := make([]byte, 5) 3258 + for i := uint64(0); i < n; i++ { 3259 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 3260 + if err != nil { 3261 + return err 3262 + } 3263 + 3264 + if !ok { 3265 + // Field doesn't exist on this type, so ignore it 3266 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 3267 + return err 3268 + } 3269 + continue 3270 + } 3271 + 3272 + switch string(nameBuf[:nameLen]) { 3273 + // t.Key (string) (string) 3274 + case "key": 3275 + 3276 + { 3277 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 3278 + if err != nil { 3279 + return err 3280 + } 3281 + 3282 + t.Key = string(sval) 3283 + } 3284 + // t.Value (string) (string) 3285 + case "value": 3286 + 3287 + { 3288 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 3289 + if err != nil { 3290 + return err 3291 + } 3292 + 3293 + t.Value = string(sval) 3294 + } 3295 + 3296 + default: 3297 + // Field doesn't exist on this type, so ignore it 3298 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 3299 + return err 3300 + } 3301 + } 3302 + } 3303 + 3304 + return nil 3305 + } 3172 3306 func (t *Pipeline_Step) MarshalCBOR(w io.Writer) error { 3173 3307 if t == nil { 3174 3308 _, err := w.Write(cbg.CborNull) ··· 3176 3310 } 3177 3311 3178 3312 cw := cbg.NewCborWriter(w) 3313 + fieldCount := 3 3314 + 3315 + if t.Environment == nil { 3316 + fieldCount-- 3317 + } 3179 3318 3180 - if _, err := cw.Write([]byte{162}); err != nil { 3319 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 3181 3320 return err 3182 3321 } 3183 3322 ··· 3226 3365 if _, err := cw.WriteString(string(t.Command)); err != nil { 3227 3366 return err 3228 3367 } 3368 + 3369 + // t.Environment ([]*tangled.Pipeline_Step_Environment_Elem) (slice) 3370 + if t.Environment != nil { 3371 + 3372 + if len("environment") > 1000000 { 3373 + return xerrors.Errorf("Value in field \"environment\" was too long") 3374 + } 3375 + 3376 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("environment"))); err != nil { 3377 + return err 3378 + } 3379 + if _, err := cw.WriteString(string("environment")); err != nil { 3380 + return err 3381 + } 3382 + 3383 + if len(t.Environment) > 8192 { 3384 + return xerrors.Errorf("Slice value in field t.Environment was too long") 3385 + } 3386 + 3387 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Environment))); err != nil { 3388 + return err 3389 + } 3390 + for _, v := range t.Environment { 3391 + if err := v.MarshalCBOR(cw); err != nil { 3392 + return err 3393 + } 3394 + 3395 + } 3396 + } 3229 3397 return nil 3230 3398 } 3231 3399 ··· 3254 3422 3255 3423 n := extra 3256 3424 3257 - nameBuf := make([]byte, 7) 3425 + nameBuf := make([]byte, 11) 3258 3426 for i := uint64(0); i < n; i++ { 3259 3427 nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 3260 3428 if err != nil { ··· 3291 3459 } 3292 3460 3293 3461 t.Command = string(sval) 3462 + } 3463 + // t.Environment ([]*tangled.Pipeline_Step_Environment_Elem) (slice) 3464 + case "environment": 3465 + 3466 + maj, extra, err = cr.ReadHeader() 3467 + if err != nil { 3468 + return err 3469 + } 3470 + 3471 + if extra > 8192 { 3472 + return fmt.Errorf("t.Environment: array too large (%d)", extra) 3473 + } 3474 + 3475 + if maj != cbg.MajArray { 3476 + return fmt.Errorf("expected cbor array") 3477 + } 3478 + 3479 + if extra > 0 { 3480 + t.Environment = make([]*Pipeline_Step_Environment_Elem, extra) 3481 + } 3482 + 3483 + for i := 0; i < int(extra); i++ { 3484 + { 3485 + var maj byte 3486 + var extra uint64 3487 + var err error 3488 + _ = maj 3489 + _ = extra 3490 + _ = err 3491 + 3492 + { 3493 + 3494 + b, err := cr.ReadByte() 3495 + if err != nil { 3496 + return err 3497 + } 3498 + if b != cbg.CborNull[0] { 3499 + if err := cr.UnreadByte(); err != nil { 3500 + return err 3501 + } 3502 + t.Environment[i] = new(Pipeline_Step_Environment_Elem) 3503 + if err := t.Environment[i].UnmarshalCBOR(cr); err != nil { 3504 + return xerrors.Errorf("unmarshaling t.Environment[i] pointer: %w", err) 3505 + } 3506 + } 3507 + 3508 + } 3509 + 3510 + } 3294 3511 } 3295 3512 3296 3513 default:
+9 -3
api/tangled/tangledpipeline.go
··· 61 61 62 62 // Pipeline_Step is a "step" in the sh.tangled.pipeline schema. 63 63 type Pipeline_Step struct { 64 - Command string `json:"command" cborgen:"command"` 65 - Name string `json:"name" cborgen:"name"` 64 + Command string `json:"command" cborgen:"command"` 65 + Environment []*Pipeline_Step_Environment_Elem `json:"environment,omitempty" cborgen:"environment,omitempty"` 66 + Name string `json:"name" cborgen:"name"` 67 + } 68 + 69 + type Pipeline_Step_Environment_Elem struct { 70 + Key string `json:"key" cborgen:"key"` 71 + Value string `json:"value" cborgen:"value"` 66 72 } 67 73 68 74 // Pipeline_TriggerMetadata is a "triggerMetadata" in the sh.tangled.pipeline schema. ··· 85 91 // Pipeline_Workflow is a "workflow" in the sh.tangled.pipeline schema. 86 92 type Pipeline_Workflow struct { 87 93 Clone *Pipeline_CloneOpts `json:"clone" cborgen:"clone"` 88 - Dependencies []Pipeline_Dependencies_Elem `json:"dependencies" cborgen:"dependencies"` 94 + Dependencies []Pipeline_Dependencies_Elem `json:"dependencies" cborgen:"dependencies"` 89 95 Environment []*Pipeline_Workflow_Environment_Elem `json:"environment" cborgen:"environment"` 90 96 Name string `json:"name" cborgen:"name"` 91 97 Steps []*Pipeline_Step `json:"steps" cborgen:"steps"`
+1
cmd/gen.go
··· 29 29 tangled.Pipeline_ManualTriggerData{}, 30 30 tangled.Pipeline_PullRequestTriggerData{}, 31 31 tangled.Pipeline_PushTriggerData{}, 32 + tangled.Pipeline_Step_Environment_Elem{}, 32 33 tangled.Pipeline_Step{}, 33 34 tangled.Pipeline_TriggerMetadata{}, 34 35 tangled.Pipeline_TriggerRepo{},
+27 -58
lexicons/pipeline.json
··· 9 9 "key": "tid", 10 10 "record": { 11 11 "type": "object", 12 - "required": [ 13 - "triggerMetadata", 14 - "workflows" 15 - ], 12 + "required": ["triggerMetadata", "workflows"], 16 13 "properties": { 17 14 "triggerMetadata": { 18 15 "type": "ref", ··· 30 27 }, 31 28 "triggerMetadata": { 32 29 "type": "object", 33 - "required": [ 34 - "kind", 35 - "repo" 36 - ], 30 + "required": ["kind", "repo"], 37 31 "properties": { 38 32 "kind": { 39 33 "type": "string", 40 - "enum": [ 41 - "push", 42 - "pull_request", 43 - "manual" 44 - ] 34 + "enum": ["push", "pull_request", "manual"] 45 35 }, 46 36 "repo": { 47 37 "type": "ref", ··· 63 53 }, 64 54 "triggerRepo": { 65 55 "type": "object", 66 - "required": [ 67 - "knot", 68 - "did", 69 - "repo", 70 - "defaultBranch" 71 - ], 56 + "required": ["knot", "did", "repo", "defaultBranch"], 72 57 "properties": { 73 58 "knot": { 74 59 "type": "string" ··· 87 72 }, 88 73 "pushTriggerData": { 89 74 "type": "object", 90 - "required": [ 91 - "ref", 92 - "newSha", 93 - "oldSha" 94 - ], 75 + "required": ["ref", "newSha", "oldSha"], 95 76 "properties": { 96 77 "ref": { 97 78 "type": "string" ··· 110 91 }, 111 92 "pullRequestTriggerData": { 112 93 "type": "object", 113 - "required": [ 114 - "sourceBranch", 115 - "targetBranch", 116 - "sourceSha", 117 - "action" 118 - ], 94 + "required": ["sourceBranch", "targetBranch", "sourceSha", "action"], 119 95 "properties": { 120 96 "sourceBranch": { 121 97 "type": "string" ··· 140 116 "type": "array", 141 117 "items": { 142 118 "type": "object", 143 - "required": [ 144 - "key", 145 - "value" 146 - ], 119 + "required": ["key", "value"], 147 120 "properties": { 148 121 "key": { 149 122 "type": "string" ··· 158 131 }, 159 132 "workflow": { 160 133 "type": "object", 161 - "required": [ 162 - "name", 163 - "dependencies", 164 - "steps", 165 - "environment", 166 - "clone" 167 - ], 134 + "required": ["name", "dependencies", "steps", "environment", "clone"], 168 135 "properties": { 169 136 "name": { 170 137 "type": "string" ··· 184 151 "type": "array", 185 152 "items": { 186 153 "type": "object", 187 - "required": [ 188 - "key", 189 - "value" 190 - ], 154 + "required": ["key", "value"], 191 155 "properties": { 192 156 "key": { 193 157 "type": "string" ··· 208 172 "type": "array", 209 173 "items": { 210 174 "type": "object", 211 - "required": [ 212 - "registry", 213 - "packages" 214 - ], 175 + "required": ["registry", "packages"], 215 176 "properties": { 216 177 "registry": { 217 178 "type": "string" ··· 227 188 }, 228 189 "cloneOpts": { 229 190 "type": "object", 230 - "required": [ 231 - "skip", 232 - "depth", 233 - "submodules" 234 - ], 191 + "required": ["skip", "depth", "submodules"], 235 192 "properties": { 236 193 "skip": { 237 194 "type": "boolean" ··· 246 203 }, 247 204 "step": { 248 205 "type": "object", 249 - "required": [ 250 - "name", 251 - "command" 252 - ], 206 + "required": ["name", "command"], 253 207 "properties": { 254 208 "name": { 255 209 "type": "string" 256 210 }, 257 211 "command": { 258 212 "type": "string" 213 + }, 214 + "environment": { 215 + "type": "array", 216 + "items": { 217 + "type": "object", 218 + "required": ["key", "value"], 219 + "properties": { 220 + "key": { 221 + "type": "string" 222 + }, 223 + "value": { 224 + "type": "string" 225 + } 226 + } 227 + } 259 228 } 260 229 } 261 230 }
+7
workflow/compile.go
··· 97 97 Command: s.Command, 98 98 Name: s.Name, 99 99 } 100 + for k, v := range s.Environment { 101 + e := &tangled.Pipeline_Step_Environment_Elem{ 102 + Key: k, 103 + Value: v, 104 + } 105 + step.Environment = append(step.Environment, e) 106 + } 100 107 cw.Steps = append(cw.Steps, &step) 101 108 } 102 109 for k, v := range w.Environment {
+3 -2
workflow/def.go
··· 45 45 } 46 46 47 47 Step struct { 48 - Name string `yaml:"name"` 49 - Command string `yaml:"command"` 48 + Name string `yaml:"name"` 49 + Command string `yaml:"command"` 50 + Environment map[string]string `yaml:"environment"` 50 51 } 51 52 52 53 StringList []string
+9
workflow/def_test.go
··· 105 105 environment: 106 106 HOME: /home/foo bar/baz 107 107 CGO_ENABLED: 1 108 + 109 + steps: 110 + - name: Something 111 + command: echo "hello" 112 + environment: 113 + FOO: bar 114 + BAZ: qux 108 115 ` 109 116 110 117 wf, err := FromFile("test.yml", []byte(yamlData)) ··· 113 120 assert.Len(t, wf.Environment, 2) 114 121 assert.Equal(t, "/home/foo bar/baz", wf.Environment["HOME"]) 115 122 assert.Equal(t, "1", wf.Environment["CGO_ENABLED"]) 123 + assert.Equal(t, "bar", wf.Steps[0].Environment["FOO"]) 124 + assert.Equal(t, "qux", wf.Steps[0].Environment["BAZ"]) 116 125 }