mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-13 16:33:26 +09:00
refactor: use the shared workflow model from actionslib (#38768)
Pairs with https://gitea.com/gitea/runner/pulls/1143. Gitea depends on `gitea.com/gitea/runner` for exactly two packages: `act/model` and `act/exprparser`, the workflow model and the expression evaluator it needs to parse workflows and to build the task payload the runner consumes. Pulling the whole runner module in for that is heavy and puts shared code in the repository of one of the two consumers. Both packages now live in `gitea.dev/actionslib` (`pkg/model`, `pkg/exprparser`), the module Gitea and the runner already share for the runner API, so the dependency on the runner repository is dropped here. ### Changes - `gitea.com/gitea/runner/act/model` -> `gitea.dev/actionslib/pkg/model`, `.../act/exprparser` -> `gitea.dev/actionslib/pkg/exprparser` (22 files, import paths only). - `routers/api/actions/runner/interceptor.go` takes the `x-runner-uuid` / `x-runner-token` names from `gitea.dev/actionslib/pkg/protocol` instead of repeating the literals the runner also has. - `go.mod`: `gitea.com/gitea/runner` removed. --------- Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
co-authored by
silverwind
Zettat123
parent
c14edf3313
commit
2087d4a1a5
@@ -11,8 +11,10 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gitea.com/gitea/runner/act/exprparser"
|
||||
"gitea.com/gitea/runner/act/model"
|
||||
"gitea.dev/actionslib/pkg/expreval"
|
||||
"gitea.dev/actionslib/pkg/exprparser"
|
||||
"gitea.dev/actionslib/pkg/model"
|
||||
|
||||
"github.com/rhysd/actionlint"
|
||||
"go.yaml.in/yaml/v4"
|
||||
)
|
||||
@@ -72,15 +74,7 @@ func ExpressionReadsMatrix(ifValue string) bool {
|
||||
// the status functions that run a job whatever its needs did rather than under the implicit success().
|
||||
// Keep in sync with act's exprparser, which owns the same list for the evaluation itself.
|
||||
func ExpressionIgnoresNeedResults(ifValue string) bool {
|
||||
return expressionCallsFunction(asIfExpression(ifValue), "always", "failure", "cancelled")
|
||||
}
|
||||
|
||||
// expressionCallsFunction reports whether any ${{ }} expression in value calls one of the functions.
|
||||
func expressionCallsFunction(value string, names ...string) bool {
|
||||
return expressionsMatch(value, func(node actionlint.ExprNode) bool {
|
||||
call, ok := node.(*actionlint.FuncCallNode)
|
||||
return ok && slices.Contains(names, strings.ToLower(call.Callee))
|
||||
})
|
||||
return expreval.CallsFunction(asIfExpression(ifValue), "always", "failure", "cancelled")
|
||||
}
|
||||
|
||||
// asIfExpression wraps an `if:` that omits the `${{ }}`, which GitHub evaluates as one expression anyway.
|
||||
@@ -95,40 +89,12 @@ func asIfExpression(ifValue string) string {
|
||||
|
||||
// expressionReadsContext reports whether value holds a ${{ }} expression reading the named context.
|
||||
func expressionReadsContext(value, contextName string) bool {
|
||||
return expressionsMatch(value, func(node actionlint.ExprNode) bool {
|
||||
return expreval.Match(value, func(node actionlint.ExprNode) bool {
|
||||
variable, ok := node.(*actionlint.VariableNode)
|
||||
return ok && strings.EqualFold(variable.Name, contextName)
|
||||
})
|
||||
}
|
||||
|
||||
// expressionsMatch reports whether any ${{ }} expression in value holds a node the predicate accepts.
|
||||
func expressionsMatch(value string, match func(node actionlint.ExprNode) bool) bool {
|
||||
parts, err := splitSubExpressions(value)
|
||||
if err != nil {
|
||||
return true // unparseable here, let the expansion report it against the real values
|
||||
}
|
||||
for _, part := range parts {
|
||||
if !part.isExpr {
|
||||
continue
|
||||
}
|
||||
// The lexer needs the closing `}}` that the scanner strips.
|
||||
expr, err := actionlint.NewExprParser().Parse(actionlint.NewExprLexer(part.text + "}}"))
|
||||
if err != nil {
|
||||
return true // unparseable here, let the expansion report it against the real values
|
||||
}
|
||||
matched := false
|
||||
actionlint.VisitExprNode(expr, func(node, _ actionlint.ExprNode, entering bool) {
|
||||
if entering && match(node) {
|
||||
matched = true
|
||||
}
|
||||
})
|
||||
if matched {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Parse(content []byte, options ...ParseOption) ([]*SingleWorkflow, error) {
|
||||
origin, err := model.ReadWorkflow(bytes.NewReader(content))
|
||||
if err != nil {
|
||||
@@ -162,8 +128,8 @@ func Parse(content []byte, options ...ParseOption) ([]*SingleWorkflow, error) {
|
||||
return nil, fmt.Errorf("invalid jobs: %w", err)
|
||||
}
|
||||
|
||||
evaluator := NewExpressionEvaluator(exprparser.NewInterpeter(&exprparser.EvaluationEnvironment{Github: pc.gitContext, Vars: pc.vars, Inputs: pc.inputs}, exprparser.Config{}))
|
||||
if workflow.RunName, err = evaluator.interpolate(workflow.RunName); err != nil {
|
||||
evaluator := expreval.New(exprparser.NewInterpeter(&exprparser.EvaluationEnvironment{Github: pc.gitContext, Vars: pc.vars, Inputs: pc.inputs}, exprparser.Config{}).Evaluate)
|
||||
if workflow.RunName, err = evaluator.Interpolate(workflow.RunName); err != nil {
|
||||
return nil, fmt.Errorf("interpolate run-name: %w", err)
|
||||
}
|
||||
|
||||
@@ -230,7 +196,7 @@ func ExpandMatrixWithNeeds(jobID string, job *Job, gitCtx *model.GithubContext,
|
||||
}}
|
||||
|
||||
// Resolve fromJson(needs.*.outputs.*) and friends into concrete matrix values.
|
||||
if err := NewExpressionEvaluator(NewInterpeter(jobID, actJob, nil, gitCtx, results, vars, inputs)).
|
||||
if err := expreval.New(NewInterpeter(jobID, actJob, nil, gitCtx, results, vars, inputs).Evaluate).
|
||||
EvaluateYamlNode(&actJob.Strategy.RawMatrix); err != nil {
|
||||
return nil, fmt.Errorf("evaluate matrix: %w", err)
|
||||
}
|
||||
@@ -253,7 +219,6 @@ func ExpandMatrixWithNeeds(jobID string, job *Job, gitCtx *model.GithubContext,
|
||||
// matrixesOf is this package's only entry to act's GetMatrixes, so that every caller is covered by
|
||||
// the filter check below. A deferred placeholder is the first thing carrying a raw matrix this far,
|
||||
// and the emitter reads its `if:` before expanding it.
|
||||
// TODO: drop the check once gitea.com/gitea/runner validates the shape itself.
|
||||
func matrixesOf(job *model.Job) ([]map[string]any, error) {
|
||||
if err := validateMatrixFilters(job); err != nil {
|
||||
return nil, err
|
||||
@@ -265,9 +230,9 @@ func matrixesOf(job *model.Job) ([]map[string]any, error) {
|
||||
return matrixes, nil
|
||||
}
|
||||
|
||||
// validateMatrixFilters rejects an `include`/`exclude` that is not a list of mappings. act asserts
|
||||
// that shape without checking, so anything else panics there; an unevaluated ${{ }} expression, which
|
||||
// is still a scalar, is the usual way to reach it.
|
||||
// validateMatrixFilters rejects an `include`/`exclude` that is not a list of mappings, so that the
|
||||
// usual way to get there, an unevaluated ${{ }} expression that is still a scalar, is named as such
|
||||
// instead of surfacing from the middle of the expansion.
|
||||
func validateMatrixFilters(job *model.Job) error {
|
||||
if job.Strategy == nil || job.Strategy.RawMatrix.Kind != yaml.MappingNode {
|
||||
return nil
|
||||
@@ -306,13 +271,13 @@ func buildMatrixCombos(jobID string, src *Job, matrixes []map[string]any, actJob
|
||||
combo.Name = jobID
|
||||
}
|
||||
combo.Strategy.RawMatrix = encodeMatrix(matrix)
|
||||
evaluator := NewExpressionEvaluator(NewInterpeter(jobID, actJob, matrix, gitCtx, results, vars, inputs))
|
||||
evaluator := expreval.New(NewInterpeter(jobID, actJob, matrix, gitCtx, results, vars, inputs).Evaluate)
|
||||
if combo.Name, err = nameWithMatrix(combo.Name, matrix, evaluator); err != nil {
|
||||
return nil, fmt.Errorf("interpolate name for job %q: %w", jobID, err)
|
||||
}
|
||||
runsOn := slices.Clone(srcRunsOn)
|
||||
for i := range runsOn {
|
||||
if runsOn[i], err = evaluator.interpolate(runsOn[i]); err != nil {
|
||||
if runsOn[i], err = evaluator.Interpolate(runsOn[i]); err != nil {
|
||||
return nil, fmt.Errorf("interpolate runs-on for job %q: %w", jobID, err)
|
||||
}
|
||||
}
|
||||
@@ -386,7 +351,7 @@ func encodeRunsOn(runsOn []string) yaml.Node {
|
||||
return node
|
||||
}
|
||||
|
||||
func nameWithMatrix(name string, m map[string]any, evaluator *ExpressionEvaluator) (string, error) {
|
||||
func nameWithMatrix(name string, m map[string]any, evaluator expreval.Evaluator) (string, error) {
|
||||
if len(m) == 0 {
|
||||
return name, nil
|
||||
}
|
||||
@@ -395,7 +360,7 @@ func nameWithMatrix(name string, m map[string]any, evaluator *ExpressionEvaluato
|
||||
return name + " " + matrixName(m), nil
|
||||
}
|
||||
|
||||
return evaluator.interpolate(name)
|
||||
return evaluator.Interpolate(name)
|
||||
}
|
||||
|
||||
func matrixName(m map[string]any) string {
|
||||
|
||||
Reference in New Issue
Block a user