1
1
package jobparser
2
2
3
3
import (
4
+ "bytes"
4
5
"fmt"
5
6
6
7
"github.com/nektos/act/pkg/model"
@@ -82,6 +83,7 @@ type Job struct {
82
83
Uses string `yaml:"uses,omitempty"`
83
84
With map [string ]interface {} `yaml:"with,omitempty"`
84
85
RawSecrets yaml.Node `yaml:"secrets,omitempty"`
86
+ RawConcurrency * model.RawConcurrency `yaml:"concurrency,omitempty"`
85
87
}
86
88
87
89
func (j * Job ) Clone () * Job {
@@ -104,6 +106,7 @@ func (j *Job) Clone() *Job {
104
106
Uses : j .Uses ,
105
107
With : j .With ,
106
108
RawSecrets : j .RawSecrets ,
109
+ RawConcurrency : j .RawConcurrency ,
107
110
}
108
111
}
109
112
@@ -241,6 +244,73 @@ func parseWorkflowDispatchInputs(inputs map[string]interface{}) ([]WorkflowDispa
241
244
return results , nil
242
245
}
243
246
247
+ func ReadWorkflowRawConcurrency (content []byte ) (* model.RawConcurrency , error ) {
248
+ w := new (model.Workflow )
249
+ err := yaml .NewDecoder (bytes .NewReader (content )).Decode (w )
250
+ return w .RawConcurrency , err
251
+ }
252
+
253
+ func EvaluateConcurrency (rc * model.RawConcurrency , jobID string , job * Job , gitCtx map [string ]any , results map [string ]* JobResult , vars map [string ]string , inputs map [string ]any ) (string , bool , error ) {
254
+ actJob := & model.Job {}
255
+ if job != nil {
256
+ actJob .Strategy = & model.Strategy {
257
+ FailFastString : job .Strategy .FailFastString ,
258
+ MaxParallelString : job .Strategy .MaxParallelString ,
259
+ RawMatrix : job .Strategy .RawMatrix ,
260
+ }
261
+ actJob .Strategy .FailFast = actJob .Strategy .GetFailFast ()
262
+ actJob .Strategy .MaxParallel = actJob .Strategy .GetMaxParallel ()
263
+ }
264
+
265
+ matrix := make (map [string ]any )
266
+ matrixes , err := actJob .GetMatrixes ()
267
+ if err != nil {
268
+ return "" , false , err
269
+ }
270
+ if len (matrixes ) > 0 {
271
+ matrix = matrixes [0 ]
272
+ }
273
+
274
+ evaluator := NewExpressionEvaluator (NewInterpeter (jobID , actJob , matrix , toGitContext (gitCtx ), results , vars , inputs ))
275
+ group := evaluator .Interpolate (rc .Group )
276
+ cancelInProgress := evaluator .Interpolate (rc .CancelInProgress )
277
+ return group , cancelInProgress == "true" , nil
278
+ }
279
+
280
+ func toGitContext (input map [string ]any ) * model.GithubContext {
281
+ gitContext := & model.GithubContext {
282
+ EventPath : asString (input ["event_path" ]),
283
+ Workflow : asString (input ["workflow" ]),
284
+ RunID : asString (input ["run_id" ]),
285
+ RunNumber : asString (input ["run_number" ]),
286
+ Actor : asString (input ["actor" ]),
287
+ Repository : asString (input ["repository" ]),
288
+ EventName : asString (input ["event_name" ]),
289
+ Sha : asString (input ["sha" ]),
290
+ Ref : asString (input ["ref" ]),
291
+ RefName : asString (input ["ref_name" ]),
292
+ RefType : asString (input ["ref_type" ]),
293
+ HeadRef : asString (input ["head_ref" ]),
294
+ BaseRef : asString (input ["base_ref" ]),
295
+ Token : asString (input ["token" ]),
296
+ Workspace : asString (input ["workspace" ]),
297
+ Action : asString (input ["action" ]),
298
+ ActionPath : asString (input ["action_path" ]),
299
+ ActionRef : asString (input ["action_ref" ]),
300
+ ActionRepository : asString (input ["action_repository" ]),
301
+ Job : asString (input ["job" ]),
302
+ RepositoryOwner : asString (input ["repository_owner" ]),
303
+ RetentionDays : asString (input ["retention_days" ]),
304
+ }
305
+
306
+ event , ok := input ["event" ].(map [string ]any )
307
+ if ok {
308
+ gitContext .Event = event
309
+ }
310
+
311
+ return gitContext
312
+ }
313
+
244
314
func ParseRawOn (rawOn * yaml.Node ) ([]* Event , error ) {
245
315
switch rawOn .Kind {
246
316
case yaml .ScalarNode :
@@ -422,3 +492,12 @@ func parseMappingNode[T any](node *yaml.Node) ([]string, []T, error) {
422
492
423
493
return scalars , datas , nil
424
494
}
495
+
496
+ func asString (v interface {}) string {
497
+ if v == nil {
498
+ return ""
499
+ } else if s , ok := v .(string ); ok {
500
+ return s
501
+ }
502
+ return ""
503
+ }
0 commit comments