package runner import ( "context" "fmt" "strings" "github.com/nektos/act/pkg/common" "github.com/nektos/act/pkg/model" log "github.com/sirupsen/logrus" ) type step interface { pre() common.Executor main() common.Executor post() common.Executor getRunContext() *RunContext getStepModel() *model.Step getEnv() *map[string]string } func runStepExecutor(step step, executor common.Executor) common.Executor { return func(ctx context.Context) error { rc := step.getRunContext() stepModel := step.getStepModel() rc.CurrentStep = stepModel.ID rc.StepResults[rc.CurrentStep] = &model.StepResult{ Outcome: model.StepStatusSuccess, Conclusion: model.StepStatusSuccess, Outputs: make(map[string]string), } err := setupEnv(ctx, step) if err != nil { return err } runStep, err := isStepEnabled(ctx, step) if err != nil { rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusFailure rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusFailure return err } if !runStep { log.Debugf("Skipping step '%s' due to '%s'", stepModel.String(), stepModel.If.Value) rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusSkipped rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusSkipped return nil } common.Logger(ctx).Infof("\u2B50 Run %s", stepModel) err = executor(ctx) if err == nil { common.Logger(ctx).Infof(" \u2705 Success - %s", stepModel) } else { common.Logger(ctx).Errorf(" \u274C Failure - %s", stepModel) rc.StepResults[rc.CurrentStep].Outcome = model.StepStatusFailure if stepModel.ContinueOnError { common.Logger(ctx).Infof("Failed but continue next step") err = nil rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusSuccess } else { rc.StepResults[rc.CurrentStep].Conclusion = model.StepStatusFailure } } return err } } func setupEnv(ctx context.Context, step step) error { rc := step.getRunContext() mergeEnv(step) err := rc.JobContainer.UpdateFromImageEnv(step.getEnv())(ctx) if err != nil { return err } err = rc.JobContainer.UpdateFromEnv((*step.getEnv())["GITHUB_ENV"], step.getEnv())(ctx) if err != nil { return err } err = rc.JobContainer.UpdateFromPath(step.getEnv())(ctx) if err != nil { return err } mergeIntoMap(step.getEnv(), step.getStepModel().GetEnv()) // step env should not be overwritten exprEval := rc.NewStepExpressionEvaluator(step) for k, v := range *step.getEnv() { (*step.getEnv())[k] = exprEval.Interpolate(v) } common.Logger(ctx).Debugf("setupEnv => %v", *step.getEnv()) return nil } func mergeEnv(step step) { env := step.getEnv() rc := step.getRunContext() job := rc.Run.Job() c := job.Container() if c != nil { mergeIntoMap(env, rc.GetEnv(), c.Env) } else { mergeIntoMap(env, rc.GetEnv()) } if (*env)["PATH"] == "" { (*env)["PATH"] = `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` } if rc.ExtraPath != nil && len(rc.ExtraPath) > 0 { p := (*env)["PATH"] (*env)["PATH"] = strings.Join(rc.ExtraPath, `:`) (*env)["PATH"] += `:` + p } mergeIntoMap(env, rc.withGithubEnv(*env)) } func isStepEnabled(ctx context.Context, step step) (bool, error) { rc := step.getRunContext() runStep, err := EvalBool(rc.NewStepExpressionEvaluator(step), step.getStepModel().If.Value) if err != nil { return false, fmt.Errorf(" \u274C Error in if-expression: \"if: %s\" (%s)", step.getStepModel().If.Value, err) } return runStep, nil } func mergeIntoMap(target *map[string]string, maps ...map[string]string) { for _, m := range maps { for k, v := range m { (*target)[k] = v } } }