+168
-1
api/tangled/cbor_gen.go
+168
-1
api/tangled/cbor_gen.go
···
4254
4255
return nil
4256
}
4257
func (t *Pipeline_PullRequestTriggerData) MarshalCBOR(w io.Writer) error {
4258
if t == nil {
4259
_, err := w.Write(cbg.CborNull)
···
4993
}
4994
4995
cw := cbg.NewCborWriter(w)
4996
-
fieldCount := 5
4997
4998
if t.Manual == nil {
4999
fieldCount--
···
5007
fieldCount--
5008
}
5009
5010
if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil {
5011
return err
5012
}
···
5088
}
5089
}
5090
5091
// t.PullRequest (tangled.Pipeline_PullRequestTriggerData) (struct)
5092
if t.PullRequest != nil {
5093
···
5220
}
5221
}
5222
5223
}
5224
// t.PullRequest (tangled.Pipeline_PullRequestTriggerData) (struct)
5225
case "pullRequest":
···
4254
4255
return nil
4256
}
4257
+
func (t *Pipeline_ScheduleTriggerData) MarshalCBOR(w io.Writer) error {
4258
+
if t == nil {
4259
+
_, err := w.Write(cbg.CborNull)
4260
+
return err
4261
+
}
4262
+
4263
+
cw := cbg.NewCborWriter(w)
4264
+
fieldCount := 1
4265
+
4266
+
if t.CronExpression == nil {
4267
+
fieldCount--
4268
+
}
4269
+
4270
+
if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil {
4271
+
return err
4272
+
}
4273
+
4274
+
// t.CronExpression (string) (string)
4275
+
if t.CronExpression != nil {
4276
+
4277
+
if len("cronExpression") > 1000000 {
4278
+
return xerrors.Errorf("Value in field \"cronExpression\" was too long")
4279
+
}
4280
+
4281
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("cronExpression"))); err != nil {
4282
+
return err
4283
+
}
4284
+
if _, err := cw.WriteString(string("cronExpression")); err != nil {
4285
+
return err
4286
+
}
4287
+
4288
+
if t.CronExpression == nil {
4289
+
if _, err := cw.Write(cbg.CborNull); err != nil {
4290
+
return err
4291
+
}
4292
+
} else {
4293
+
if len(*t.CronExpression) > 1000000 {
4294
+
return xerrors.Errorf("Value in field t.CronExpression was too long")
4295
+
}
4296
+
4297
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.CronExpression))); err != nil {
4298
+
return err
4299
+
}
4300
+
if _, err := cw.WriteString(string(*t.CronExpression)); err != nil {
4301
+
return err
4302
+
}
4303
+
}
4304
+
}
4305
+
return nil
4306
+
}
4307
+
4308
+
func (t *Pipeline_ScheduleTriggerData) UnmarshalCBOR(r io.Reader) (err error) {
4309
+
*t = Pipeline_ScheduleTriggerData{}
4310
+
4311
+
cr := cbg.NewCborReader(r)
4312
+
4313
+
maj, extra, err := cr.ReadHeader()
4314
+
if err != nil {
4315
+
return err
4316
+
}
4317
+
defer func() {
4318
+
if err == io.EOF {
4319
+
err = io.ErrUnexpectedEOF
4320
+
}
4321
+
}()
4322
+
4323
+
if maj != cbg.MajMap {
4324
+
return fmt.Errorf("cbor input should be of type map")
4325
+
}
4326
+
4327
+
if extra > cbg.MaxLength {
4328
+
return fmt.Errorf("Pipeline_ScheduleTriggerData: map struct too large (%d)", extra)
4329
+
}
4330
+
4331
+
n := extra
4332
+
4333
+
nameBuf := make([]byte, 14)
4334
+
for i := uint64(0); i < n; i++ {
4335
+
nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000)
4336
+
if err != nil {
4337
+
return err
4338
+
}
4339
+
4340
+
if !ok {
4341
+
// Field doesn't exist on this type, so ignore it
4342
+
if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil {
4343
+
return err
4344
+
}
4345
+
continue
4346
+
}
4347
+
4348
+
switch string(nameBuf[:nameLen]) {
4349
+
// t.CronExpression (string) (string)
4350
+
case "cronExpression":
4351
+
4352
+
{
4353
+
b, err := cr.ReadByte()
4354
+
if err != nil {
4355
+
return err
4356
+
}
4357
+
if b != cbg.CborNull[0] {
4358
+
if err := cr.UnreadByte(); err != nil {
4359
+
return err
4360
+
}
4361
+
4362
+
sval, err := cbg.ReadStringWithMax(cr, 1000000)
4363
+
if err != nil {
4364
+
return err
4365
+
}
4366
+
4367
+
t.CronExpression = (*string)(&sval)
4368
+
}
4369
+
}
4370
+
4371
+
default:
4372
+
// Field doesn't exist on this type, so ignore it
4373
+
if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil {
4374
+
return err
4375
+
}
4376
+
}
4377
+
}
4378
+
4379
+
return nil
4380
+
}
4381
func (t *Pipeline_PullRequestTriggerData) MarshalCBOR(w io.Writer) error {
4382
if t == nil {
4383
_, err := w.Write(cbg.CborNull)
···
5117
}
5118
5119
cw := cbg.NewCborWriter(w)
5120
+
fieldCount := 6
5121
5122
if t.Manual == nil {
5123
fieldCount--
···
5131
fieldCount--
5132
}
5133
5134
+
if t.Schedule == nil {
5135
+
fieldCount--
5136
+
}
5137
+
5138
if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil {
5139
return err
5140
}
···
5216
}
5217
}
5218
5219
+
// t.Schedule (tangled.Pipeline_ScheduleTriggerData) (struct)
5220
+
if t.Schedule != nil {
5221
+
5222
+
if len("schedule") > 1000000 {
5223
+
return xerrors.Errorf("Value in field \"schedule\" was too long")
5224
+
}
5225
+
5226
+
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("schedule"))); err != nil {
5227
+
return err
5228
+
}
5229
+
if _, err := cw.WriteString(string("schedule")); err != nil {
5230
+
return err
5231
+
}
5232
+
5233
+
if err := t.Schedule.MarshalCBOR(cw); err != nil {
5234
+
return err
5235
+
}
5236
+
}
5237
+
5238
// t.PullRequest (tangled.Pipeline_PullRequestTriggerData) (struct)
5239
if t.PullRequest != nil {
5240
···
5367
}
5368
}
5369
5370
+
}
5371
+
// t.Schedule (tangled.Pipeline_ScheduleTriggerData) (struct)
5372
+
case "schedule":
5373
+
5374
+
{
5375
+
5376
+
b, err := cr.ReadByte()
5377
+
if err != nil {
5378
+
return err
5379
+
}
5380
+
if b != cbg.CborNull[0] {
5381
+
if err := cr.UnreadByte(); err != nil {
5382
+
return err
5383
+
}
5384
+
t.Schedule = new(Pipeline_ScheduleTriggerData)
5385
+
if err := t.Schedule.UnmarshalCBOR(cr); err != nil {
5386
+
return xerrors.Errorf("unmarshaling t.Schedule pointer: %w", err)
5387
+
}
5388
+
}
5389
+
5390
}
5391
// t.PullRequest (tangled.Pipeline_PullRequestTriggerData) (struct)
5392
case "pullRequest":
+6
api/tangled/tangledpipeline.go
+6
api/tangled/tangledpipeline.go
···
55
Ref string `json:"ref" cborgen:"ref"`
56
}
57
58
// Pipeline_TriggerMetadata is a "triggerMetadata" in the sh.tangled.pipeline schema.
59
type Pipeline_TriggerMetadata struct {
60
Kind string `json:"kind" cborgen:"kind"`
···
62
PullRequest *Pipeline_PullRequestTriggerData `json:"pullRequest,omitempty" cborgen:"pullRequest,omitempty"`
63
Push *Pipeline_PushTriggerData `json:"push,omitempty" cborgen:"push,omitempty"`
64
Repo *Pipeline_TriggerRepo `json:"repo" cborgen:"repo"`
65
}
66
67
// Pipeline_TriggerRepo is a "triggerRepo" in the sh.tangled.pipeline schema.
···
55
Ref string `json:"ref" cborgen:"ref"`
56
}
57
58
+
// Pipeline_ScheduleTriggerData is a "scheduleTriggerData" in the sh.tangled.pipeline schema.
59
+
type Pipeline_ScheduleTriggerData struct {
60
+
CronExpression *string `json:"cronExpression,omitempty" cborgen:"cronExpression,omitempty"`
61
+
}
62
+
63
// Pipeline_TriggerMetadata is a "triggerMetadata" in the sh.tangled.pipeline schema.
64
type Pipeline_TriggerMetadata struct {
65
Kind string `json:"kind" cborgen:"kind"`
···
67
PullRequest *Pipeline_PullRequestTriggerData `json:"pullRequest,omitempty" cborgen:"pullRequest,omitempty"`
68
Push *Pipeline_PushTriggerData `json:"push,omitempty" cborgen:"push,omitempty"`
69
Repo *Pipeline_TriggerRepo `json:"repo" cborgen:"repo"`
70
+
Schedule *Pipeline_ScheduleTriggerData `json:"schedule,omitempty" cborgen:"schedule,omitempty"`
71
}
72
73
// Pipeline_TriggerRepo is a "triggerRepo" in the sh.tangled.pipeline schema.
+1
cmd/cborgen/cborgen.go
+1
cmd/cborgen/cborgen.go
+2
docs/spindle/pipeline.md
+2
docs/spindle/pipeline.md
···
18
- `event`: This is a **required** field that defines when your workflow should run. It's a list that can take one or more of the following values:
19
- `push`: The workflow should run every time a commit is pushed to the repository.
20
- `pull_request`: The workflow should run every time a pull request is made or updated.
21
- `manual`: The workflow can be triggered manually.
22
- `branch`: Defines which branches the workflow should run for. If used with the `push` event, commits to the branch(es) listed here will trigger the workflow. If used with the `pull_request` event, updates to pull requests targeting the branch(es) listed here will trigger the workflow. This field has no effect with the `manual` event. Supports glob patterns using `*` and `**` (e.g., `main`, `develop`, `release-*`). Either `branch` or `tag` (or both) must be specified for `push` events.
23
- `tag`: Defines which tags the workflow should run for. Only used with the `push` event - when tags matching the pattern(s) listed here are pushed, the workflow will trigger. This field has no effect with `pull_request` or `manual` events. Supports glob patterns using `*` and `**` (e.g., `v*`, `v1.*`, `release-**`). Either `branch` or `tag` (or both) must be specified for `push` events.
24
25
For example, if you'd like to define a workflow that runs when commits are pushed to the `main` and `develop` branches, or when pull requests that target the `main` branch are updated, or manually, you can do so with:
26
···
18
- `event`: This is a **required** field that defines when your workflow should run. It's a list that can take one or more of the following values:
19
- `push`: The workflow should run every time a commit is pushed to the repository.
20
- `pull_request`: The workflow should run every time a pull request is made or updated.
21
+
- `schedule`: The workflow should run on a schedule.
22
- `manual`: The workflow can be triggered manually.
23
- `branch`: Defines which branches the workflow should run for. If used with the `push` event, commits to the branch(es) listed here will trigger the workflow. If used with the `pull_request` event, updates to pull requests targeting the branch(es) listed here will trigger the workflow. This field has no effect with the `manual` event. Supports glob patterns using `*` and `**` (e.g., `main`, `develop`, `release-*`). Either `branch` or `tag` (or both) must be specified for `push` events.
24
- `tag`: Defines which tags the workflow should run for. Only used with the `push` event - when tags matching the pattern(s) listed here are pushed, the workflow will trigger. This field has no effect with `pull_request` or `manual` events. Supports glob patterns using `*` and `**` (e.g., `v*`, `v1.*`, `release-**`). Either `branch` or `tag` (or both) must be specified for `push` events.
25
+
- `cron`: This field is **required** when using the `schedule` event. It defines the cron expression that specifies when the workflow should run. The cron syntax follows the [standard crontab format](https://www.man7.org/linux/man-pages/man5/crontab.5.html). For example, to run a workflow every day at midnight, you would use `0 0 * * *`. All jobs are run in UTC.
26
27
For example, if you'd like to define a workflow that runs when commits are pushed to the `main` and `develop` branches, or when pull requests that target the `main` branch are updated, or manually, you can do so with:
28
+4
-1
go.mod
+4
-1
go.mod
···
41
github.com/sethvargo/go-envconfig v1.1.0
42
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
43
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
44
-
github.com/stretchr/testify v1.10.0
45
github.com/urfave/cli/v3 v3.3.3
46
github.com/whyrusleeping/cbor-gen v0.3.1
47
github.com/wyatt915/goldmark-treeblood v0.0.1
···
106
github.com/emirpasic/gods v1.18.1 // indirect
107
github.com/felixge/httpsnoop v1.0.4 // indirect
108
github.com/fsnotify/fsnotify v1.6.0 // indirect
109
github.com/go-enry/go-oniguruma v1.2.1 // indirect
110
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
111
github.com/go-git/go-billy/v5 v5.6.2 // indirect
···
147
github.com/ipfs/go-log v1.0.5 // indirect
148
github.com/ipfs/go-log/v2 v2.6.0 // indirect
149
github.com/ipfs/go-metrics-interface v0.3.0 // indirect
150
github.com/json-iterator/go v1.1.12 // indirect
151
github.com/kevinburke/ssh_config v1.2.0 // indirect
152
github.com/klauspost/compress v1.18.0 // indirect
···
184
github.com/prometheus/common v0.64.0 // indirect
185
github.com/prometheus/procfs v0.16.1 // indirect
186
github.com/rivo/uniseg v0.4.7 // indirect
187
github.com/ryanuber/go-glob v1.0.0 // indirect
188
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
189
github.com/spaolacci/murmur3 v1.1.0 // indirect
···
41
github.com/sethvargo/go-envconfig v1.1.0
42
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c
43
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef
44
+
github.com/stretchr/testify v1.11.1
45
github.com/urfave/cli/v3 v3.3.3
46
github.com/whyrusleeping/cbor-gen v0.3.1
47
github.com/wyatt915/goldmark-treeblood v0.0.1
···
106
github.com/emirpasic/gods v1.18.1 // indirect
107
github.com/felixge/httpsnoop v1.0.4 // indirect
108
github.com/fsnotify/fsnotify v1.6.0 // indirect
109
+
github.com/go-co-op/gocron/v2 v2.18.2 // indirect
110
github.com/go-enry/go-oniguruma v1.2.1 // indirect
111
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
112
github.com/go-git/go-billy/v5 v5.6.2 // indirect
···
148
github.com/ipfs/go-log v1.0.5 // indirect
149
github.com/ipfs/go-log/v2 v2.6.0 // indirect
150
github.com/ipfs/go-metrics-interface v0.3.0 // indirect
151
+
github.com/jonboulle/clockwork v0.5.0 // indirect
152
github.com/json-iterator/go v1.1.12 // indirect
153
github.com/kevinburke/ssh_config v1.2.0 // indirect
154
github.com/klauspost/compress v1.18.0 // indirect
···
186
github.com/prometheus/common v0.64.0 // indirect
187
github.com/prometheus/procfs v0.16.1 // indirect
188
github.com/rivo/uniseg v0.4.7 // indirect
189
+
github.com/robfig/cron/v3 v3.0.1 // indirect
190
github.com/ryanuber/go-glob v1.0.0 // indirect
191
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
192
github.com/spaolacci/murmur3 v1.1.0 // indirect
+8
go.sum
+8
go.sum
···
160
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
161
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
162
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
163
github.com/go-enry/go-enry/v2 v2.9.2 h1:giOQAtCgBX08kosrX818DCQJTCNtKwoPBGu0qb6nKTY=
164
github.com/go-enry/go-enry/v2 v2.9.2/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
165
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
···
306
github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
307
github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
308
github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
309
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
310
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
311
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
···
444
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
445
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
446
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
447
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
448
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
449
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
···
481
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
482
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
483
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
484
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
485
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
486
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
···
160
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
161
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
162
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
163
+
github.com/go-co-op/gocron/v2 v2.18.2 h1:+5VU41FUXPWSPKLXZQ/77SGzUiPCcakU0v7ENc2H20Q=
164
+
github.com/go-co-op/gocron/v2 v2.18.2/go.mod h1:Zii6he+Zfgy5W9B+JKk/KwejFOW0kZTFvHtwIpR4aBI=
165
github.com/go-enry/go-enry/v2 v2.9.2 h1:giOQAtCgBX08kosrX818DCQJTCNtKwoPBGu0qb6nKTY=
166
github.com/go-enry/go-enry/v2 v2.9.2/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
167
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
···
308
github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8=
309
github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
310
github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY=
311
+
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
312
+
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
313
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
314
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
315
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
···
448
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
449
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
450
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
451
+
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
452
+
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
453
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
454
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
455
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
···
487
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
488
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
489
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
490
+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
491
+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
492
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
493
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
494
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
+13
lexicons/pipeline/pipeline.json
+13
lexicons/pipeline/pipeline.json
···
40
"enum": [
41
"push",
42
"pull_request",
43
+
"schedule",
44
"manual"
45
]
46
},
···
56
"type": "ref",
57
"ref": "#pullRequestTriggerData"
58
},
59
+
"schedule": {
60
+
"type": "ref",
61
+
"ref": "#scheduleTriggerData"
62
+
},
63
"manual": {
64
"type": "ref",
65
"ref": "#manualTriggerData"
···
138
}
139
}
140
},
141
+
"scheduleTriggerData": {
142
+
"type": "object",
143
+
"properties": {
144
+
"cronExpression": {
145
+
"type": "string"
146
+
}
147
+
}
148
+
},
149
"manualTriggerData": {
150
"type": "object",
151
"properties": {
+18
spindle/server.go
+18
spindle/server.go
···
7
"fmt"
8
"log/slog"
9
"net/http"
10
11
"github.com/go-chi/chi/v5"
12
"tangled.org/core/api/tangled"
13
"tangled.org/core/eventconsumer"
14
"tangled.org/core/eventconsumer/cursor"
···
47
ks *eventconsumer.Consumer
48
res *idresolver.Resolver
49
vault secrets.Manager
50
}
51
52
// New creates a new Spindle server with the provided configuration and engines.
···
116
117
resolver := idresolver.DefaultResolver(cfg.Server.PlcUrl)
118
119
spindle := &Spindle{
120
jc: jc,
121
e: e,
···
127
cfg: cfg,
128
res: resolver,
129
vault: vault,
130
}
131
132
err = e.AddSpindle(rbacDomain)
···
200
return s.e
201
}
202
203
// Start starts the Spindle server (blocking).
204
func (s *Spindle) Start(ctx context.Context) error {
205
// starts a job queue runner in the background
···
211
defer stopper.Stop()
212
}
213
214
go func() {
215
s.l.Info("starting knot event consumer")
216
s.ks.Start(ctx)
···
7
"fmt"
8
"log/slog"
9
"net/http"
10
+
"time"
11
12
"github.com/go-chi/chi/v5"
13
+
"github.com/go-co-op/gocron/v2"
14
+
15
"tangled.org/core/api/tangled"
16
"tangled.org/core/eventconsumer"
17
"tangled.org/core/eventconsumer/cursor"
···
50
ks *eventconsumer.Consumer
51
res *idresolver.Resolver
52
vault secrets.Manager
53
+
crons gocron.Scheduler
54
}
55
56
// New creates a new Spindle server with the provided configuration and engines.
···
120
121
resolver := idresolver.DefaultResolver(cfg.Server.PlcUrl)
122
123
+
scheduler, err := gocron.NewScheduler(gocron.WithLocation(time.UTC))
124
+
if err != nil {
125
+
return nil, fmt.Errorf("failed to create cron scheduler: %w", err)
126
+
}
127
+
defer func() { _ = scheduler.Shutdown() }()
128
+
129
spindle := &Spindle{
130
jc: jc,
131
e: e,
···
137
cfg: cfg,
138
res: resolver,
139
vault: vault,
140
+
crons: scheduler,
141
}
142
143
err = e.AddSpindle(rbacDomain)
···
211
return s.e
212
}
213
214
+
// Scheduler returns the cron scheduler instance.
215
+
func (s *Spindle) Scheduler() *gocron.Scheduler {
216
+
return &s.crons
217
+
}
218
+
219
// Start starts the Spindle server (blocking).
220
func (s *Spindle) Start(ctx context.Context) error {
221
// starts a job queue runner in the background
···
227
defer stopper.Stop()
228
}
229
230
+
s.crons.Start()
231
+
232
go func() {
233
s.l.Info("starting knot event consumer")
234
s.ks.Start(ctx)
+20
workflow/def.go
+20
workflow/def.go
···
9
"tangled.org/core/api/tangled"
10
11
"github.com/bmatcuk/doublestar/v4"
12
"github.com/go-git/go-git/v5/plumbing"
13
"gopkg.in/yaml.v3"
14
)
···
36
Event StringList `yaml:"event"`
37
Branch StringList `yaml:"branch"` // required for pull_request; for push, either branch or tag must be specified
38
Tag StringList `yaml:"tag"` // optional; only applies to push events
39
}
40
41
CloneOpts struct {
···
54
55
TriggerKindPush TriggerKind = "push"
56
TriggerKindPullRequest TriggerKind = "pull_request"
57
TriggerKindManual TriggerKind = "manual"
58
)
59
···
147
match = match && matched
148
}
149
150
return match, nil
151
}
152
···
9
"tangled.org/core/api/tangled"
10
11
"github.com/bmatcuk/doublestar/v4"
12
+
"github.com/go-co-op/gocron/v2"
13
"github.com/go-git/go-git/v5/plumbing"
14
"gopkg.in/yaml.v3"
15
)
···
37
Event StringList `yaml:"event"`
38
Branch StringList `yaml:"branch"` // required for pull_request; for push, either branch or tag must be specified
39
Tag StringList `yaml:"tag"` // optional; only applies to push events
40
+
Cron StringList `yaml:"cron"` // required for schedule events
41
}
42
43
CloneOpts struct {
···
56
57
TriggerKindPush TriggerKind = "push"
58
TriggerKindPullRequest TriggerKind = "pull_request"
59
+
TriggerKindSchedule TriggerKind = "schedule"
60
TriggerKindManual TriggerKind = "manual"
61
)
62
···
150
match = match && matched
151
}
152
153
+
// apply cron constraints for schedules
154
+
if trigger.Schedule != nil {
155
+
s, _ := gocron.NewScheduler()
156
+
157
+
_, err := s.NewJob(gocron.CronJob(
158
+
*trigger.Schedule.CronExpression,
159
+
false,
160
+
),
161
+
gocron.NewTask(
162
+
func() {},
163
+
),
164
+
)
165
+
if err != nil {
166
+
return false, err
167
+
}
168
+
}
169
+
170
return match, nil
171
}
172
+16
workflow/def_test.go
+16
workflow/def_test.go
···
68
assert.ElementsMatch(t, []string{"v*"}, wf.When[0].Tag)
69
}
70
71
+
func TestUnmarshalWorkflowWithCron(t *testing.T) {
72
+
yamlData := `
73
+
when:
74
+
- event: ["schedule"]
75
+
cron: "0 0 * * *"`
76
+
77
+
wf, err := FromFile("test.yml", []byte(yamlData))
78
+
assert.NoError(t, err, "YAML should unmarshal without error")
79
+
80
+
assert.Len(t, wf.When, 1, "Should have one constraint")
81
+
assert.ElementsMatch(t, []string{"schedule"}, wf.When[0].Event)
82
+
assert.ElementsMatch(t, []string{"0 0 * * *"}, wf.When[0].Cron)
83
+
84
+
assert.False(t, wf.CloneOpts.Skip, "Skip should default to false")
85
+
}
86
+
87
func TestMatchesPattern(t *testing.T) {
88
tests := []struct {
89
name string