mirror of
https://gitea.com/gitea/act_runner
synced 2026-09-21 19:37:07 +02:00
fix: fail the step or job whose expression cannot be interpolated (#1199)
An expression that failed to evaluate was logged and replaced by an empty string, so a `run:` step executed an empty script and reported success. The same swallow covered `shell:`, `working-directory:`, step `env:`, `with:`, `uses:`, the job's `env:`, `container:`, `services:`, `runs-on:` and outputs, and a called workflow's `with:` and `secrets:`. Every interpolation now propagates its error as actions/runner does: step-level values fail the step, job-level values fail the job at setup, `timeout-minutes` logs the error and runs unbounded, and a job or step name keeps its source text. `defaults.run` and a called workflow's inputs and secrets are resolved once at job setup with the job context rather than per step, and the job's image is resolved once, so host mode and `ImageOS` derive from the image the job started with. Closes https://gitea.com/gitea/runner/issues/392 Closes https://gitea.com/gitea/runner/issues/555 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: silverwind <2021+silverwind@noreply.gitea.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/1199 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
committed by
silverwind
co-authored by
silverwind
silverwind
parent
7f53eca716
commit
1745c7c841
@@ -7,6 +7,7 @@ package runner
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strconv"
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
"gitea.dev/actionslib/pkg/model"
|
||||
)
|
||||
|
||||
func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step actionStep) map[string]string {
|
||||
func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step actionStep) (map[string]string, error) {
|
||||
env := make(map[string]string)
|
||||
stepEnv := *step.getEnv()
|
||||
for k, v := range stepEnv {
|
||||
@@ -47,14 +48,17 @@ func evaluateCompositeInputAndEnv(ctx context.Context, parent *RunContext, step
|
||||
env[envKey] = value
|
||||
} else {
|
||||
// defaults could contain expressions
|
||||
env[envKey] = ee.Interpolate(ctx, input.Default)
|
||||
var err error
|
||||
if env[envKey], err = ee.Interpolate(ctx, input.Default); err != nil {
|
||||
return nil, fmt.Errorf("unable to interpolate the default of input %s: %w", inputID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
gh := step.getGithubContext(ctx)
|
||||
env["GITHUB_ACTION_REPOSITORY"] = gh.ActionRepository
|
||||
env["GITHUB_ACTION_REF"] = gh.ActionRef
|
||||
|
||||
return env
|
||||
return env, nil
|
||||
}
|
||||
|
||||
func (rc *RunContext) setCompositeActionEnv(env map[string]string) {
|
||||
@@ -66,8 +70,11 @@ func (rc *RunContext) setCompositeActionEnv(env map[string]string) {
|
||||
}
|
||||
}
|
||||
|
||||
func newCompositeRunContext(ctx context.Context, parent *RunContext, step actionStep, actionPath string) *RunContext {
|
||||
env := evaluateCompositeInputAndEnv(ctx, parent, step)
|
||||
func newCompositeRunContext(ctx context.Context, parent *RunContext, step actionStep, actionPath string) (*RunContext, error) {
|
||||
env, err := evaluateCompositeInputAndEnv(ctx, parent, step)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// run with the global config but without secrets
|
||||
configCopy := *parent.Config
|
||||
@@ -87,20 +94,21 @@ func newCompositeRunContext(ctx context.Context, parent *RunContext, step action
|
||||
},
|
||||
},
|
||||
},
|
||||
Config: &configCopy,
|
||||
StepResults: map[string]*model.StepResult{},
|
||||
JobContainer: parent.JobContainer,
|
||||
ActionPath: actionPath,
|
||||
GlobalEnv: parent.GlobalEnv,
|
||||
Masks: parent.Masks,
|
||||
ExtraPath: parent.ExtraPath,
|
||||
Parent: parent,
|
||||
EventJSON: parent.EventJSON,
|
||||
Config: &configCopy,
|
||||
StepResults: map[string]*model.StepResult{},
|
||||
JobContainer: parent.JobContainer,
|
||||
ActionPath: actionPath,
|
||||
GlobalEnv: parent.GlobalEnv,
|
||||
Masks: parent.Masks,
|
||||
ExtraPath: parent.ExtraPath,
|
||||
Parent: parent,
|
||||
EventJSON: parent.EventJSON,
|
||||
platformImage: parent.platformImage,
|
||||
}
|
||||
compositerc.setCompositeActionEnv(env)
|
||||
compositerc.ExprEval = compositerc.NewExpressionEvaluator(ctx)
|
||||
|
||||
return compositerc
|
||||
return compositerc, nil
|
||||
}
|
||||
|
||||
// appendUniqueMasks appends the masks from src to dst, skipping any mask that
|
||||
@@ -121,7 +129,10 @@ func execAsComposite(step actionStep) common.Executor {
|
||||
action := step.getActionModel()
|
||||
|
||||
return func(ctx context.Context) error {
|
||||
compositeRC := step.getCompositeRunContext(ctx)
|
||||
compositeRC, err := step.getCompositeRunContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
steps := step.getCompositeSteps()
|
||||
|
||||
@@ -131,14 +142,17 @@ func execAsComposite(step actionStep) common.Executor {
|
||||
|
||||
ctx = WithCompositeLogger(ctx, &compositeRC.Masks)
|
||||
|
||||
err := steps.main(ctx)
|
||||
err = steps.main(ctx)
|
||||
|
||||
// Map outputs from composite RunContext to job RunContext
|
||||
eval := compositeRC.NewExpressionEvaluator(ctx)
|
||||
for outputName, output := range action.Outputs {
|
||||
rc.setOutput(ctx, map[string]string{
|
||||
"name": outputName,
|
||||
}, eval.Interpolate(ctx, output.Value))
|
||||
value, outputErr := eval.Interpolate(ctx, output.Value)
|
||||
if outputErr != nil {
|
||||
err = errors.Join(err, fmt.Errorf("unable to interpolate output %s: %w", outputName, outputErr))
|
||||
continue
|
||||
}
|
||||
rc.setOutput(ctx, map[string]string{"name": outputName}, value)
|
||||
}
|
||||
|
||||
// compositeRC.Masks is seeded with rc.Masks (see newCompositeRunContext)
|
||||
|
||||
Reference in New Issue
Block a user