Skip to content

Commit

Permalink
Support concurrency (#124)
Browse files Browse the repository at this point in the history
To support `concurrency` syntax for Gitea Actions

Gitea PR: go-gitea/gitea#32751

Reviewed-on: https://gitea.com/gitea/act/pulls/124
Reviewed-by: Lunny Xiao <[email protected]>
Co-authored-by: Zettat123 <[email protected]>
Co-committed-by: Zettat123 <[email protected]>
  • Loading branch information
Zettat123 authored and Lunny Xiao committed Feb 11, 2025
1 parent 1656206 commit ec091ad
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 2 deletions.
3 changes: 2 additions & 1 deletion pkg/jobparser/interpeter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func NewInterpeter(
gitCtx *model.GithubContext,
results map[string]*JobResult,
vars map[string]string,
inputs map[string]interface{},
) exprparser.Interpreter {
strategy := make(map[string]interface{})
if job.Strategy != nil {
Expand Down Expand Up @@ -62,7 +63,7 @@ func NewInterpeter(
Strategy: strategy,
Matrix: matrix,
Needs: using,
Inputs: nil, // not supported yet
Inputs: inputs,
Vars: vars,
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/jobparser/jobparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func Parse(content []byte, options ...ParseOption) ([]*SingleWorkflow, error) {
job.Name = id
}
job.Strategy.RawMatrix = encodeMatrix(matrix)
evaluator := NewExpressionEvaluator(NewInterpeter(id, origin.GetJob(id), matrix, pc.gitContext, results, pc.vars))
evaluator := NewExpressionEvaluator(NewInterpeter(id, origin.GetJob(id), matrix, pc.gitContext, results, pc.vars, nil))
job.Name = nameWithMatrix(job.Name, matrix, evaluator)
runsOn := origin.GetJob(id).RunsOn()
for i, v := range runsOn {
Expand Down
79 changes: 79 additions & 0 deletions pkg/jobparser/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jobparser

import (
"bytes"
"fmt"

"github.com/nektos/act/pkg/model"
Expand Down Expand Up @@ -82,6 +83,7 @@ type Job struct {
Uses string `yaml:"uses,omitempty"`
With map[string]interface{} `yaml:"with,omitempty"`
RawSecrets yaml.Node `yaml:"secrets,omitempty"`
RawConcurrency *model.RawConcurrency `yaml:"concurrency,omitempty"`
}

func (j *Job) Clone() *Job {
Expand All @@ -104,6 +106,7 @@ func (j *Job) Clone() *Job {
Uses: j.Uses,
With: j.With,
RawSecrets: j.RawSecrets,
RawConcurrency: j.RawConcurrency,
}
}

Expand Down Expand Up @@ -241,6 +244,73 @@ func parseWorkflowDispatchInputs(inputs map[string]interface{}) ([]WorkflowDispa
return results, nil
}

func ReadWorkflowRawConcurrency(content []byte) (*model.RawConcurrency, error) {
w := new(model.Workflow)
err := yaml.NewDecoder(bytes.NewReader(content)).Decode(w)
return w.RawConcurrency, err
}

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) {
actJob := &model.Job{}
if job != nil {
actJob.Strategy = &model.Strategy{
FailFastString: job.Strategy.FailFastString,
MaxParallelString: job.Strategy.MaxParallelString,
RawMatrix: job.Strategy.RawMatrix,
}
actJob.Strategy.FailFast = actJob.Strategy.GetFailFast()
actJob.Strategy.MaxParallel = actJob.Strategy.GetMaxParallel()
}

matrix := make(map[string]any)
matrixes, err := actJob.GetMatrixes()
if err != nil {
return "", false, err
}
if len(matrixes) > 0 {
matrix = matrixes[0]
}

evaluator := NewExpressionEvaluator(NewInterpeter(jobID, actJob, matrix, toGitContext(gitCtx), results, vars, inputs))
group := evaluator.Interpolate(rc.Group)
cancelInProgress := evaluator.Interpolate(rc.CancelInProgress)
return group, cancelInProgress == "true", nil
}

func toGitContext(input map[string]any) *model.GithubContext {
gitContext := &model.GithubContext{
EventPath: asString(input["event_path"]),
Workflow: asString(input["workflow"]),
RunID: asString(input["run_id"]),
RunNumber: asString(input["run_number"]),
Actor: asString(input["actor"]),
Repository: asString(input["repository"]),
EventName: asString(input["event_name"]),
Sha: asString(input["sha"]),
Ref: asString(input["ref"]),
RefName: asString(input["ref_name"]),
RefType: asString(input["ref_type"]),
HeadRef: asString(input["head_ref"]),
BaseRef: asString(input["base_ref"]),
Token: asString(input["token"]),
Workspace: asString(input["workspace"]),
Action: asString(input["action"]),
ActionPath: asString(input["action_path"]),
ActionRef: asString(input["action_ref"]),
ActionRepository: asString(input["action_repository"]),
Job: asString(input["job"]),
RepositoryOwner: asString(input["repository_owner"]),
RetentionDays: asString(input["retention_days"]),
}

event, ok := input["event"].(map[string]any)
if ok {
gitContext.Event = event
}

return gitContext
}

func ParseRawOn(rawOn *yaml.Node) ([]*Event, error) {
switch rawOn.Kind {
case yaml.ScalarNode:
Expand Down Expand Up @@ -422,3 +492,12 @@ func parseMappingNode[T any](node *yaml.Node) ([]string, []T, error) {

return scalars, datas, nil
}

func asString(v interface{}) string {
if v == nil {
return ""
} else if s, ok := v.(string); ok {
return s
}
return ""
}
9 changes: 9 additions & 0 deletions pkg/model/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Workflow struct {
Env map[string]string `yaml:"env"`
Jobs map[string]*Job `yaml:"jobs"`
Defaults Defaults `yaml:"defaults"`

RawConcurrency *RawConcurrency `yaml:"concurrency"` // For Gitea
}

// On events for the workflow
Expand Down Expand Up @@ -769,3 +771,10 @@ func decodeNode(node yaml.Node, out interface{}) bool {
}
return true
}

// For Gitea
// RawConcurrency represents a workflow concurrency or a job concurrency with uninterpolated options
type RawConcurrency struct {
Group string `yaml:"group,omitempty"`
CancelInProgress string `yaml:"cancel-in-progress,omitempty"`
}

0 comments on commit ec091ad

Please sign in to comment.