diff --git a/pkg/runner/action.go b/pkg/runner/action.go
index 3346fbf8bd1..5faaaffbda8 100644
--- a/pkg/runner/action.go
+++ b/pkg/runner/action.go
@@ -362,170 +362,6 @@ func newStepContainer(ctx context.Context, step step, image string, cmd []string
 	return stepContainer
 }
 
-func execAsComposite(step actionStep, containerActionDir string) common.Executor {
-	rc := step.getRunContext()
-	action := step.getActionModel()
-
-	return func(ctx context.Context) error {
-		// Disable some features of composite actions, only for feature parity with github
-		for _, compositeStep := range action.Runs.Steps {
-			if err := compositeStep.Validate(rc.Config.CompositeRestrictions); err != nil {
-				return err
-			}
-		}
-
-		eval := rc.NewExpressionEvaluator()
-
-		inputs := make(map[string]interface{})
-		for k, input := range action.Inputs {
-			inputs[k] = eval.Interpolate(input.Default)
-		}
-		if step.getStepModel().With != nil {
-			for k, v := range step.getStepModel().With {
-				inputs[k] = eval.Interpolate(v)
-			}
-		}
-
-		env := make(map[string]string)
-		for k, v := range rc.Env {
-			env[k] = eval.Interpolate(v)
-		}
-		for k, v := range step.getStepModel().Environment() {
-			env[k] = eval.Interpolate(v)
-		}
-
-		// run with the global config but without secrets
-		configCopy := *rc.Config
-		configCopy.Secrets = nil
-
-		// create a run context for the composite action to run in
-		compositerc := &RunContext{
-			Name:    rc.Name,
-			JobName: rc.JobName,
-			Run: &model.Run{
-				JobID: "composite-job",
-				Workflow: &model.Workflow{
-					Name: rc.Run.Workflow.Name,
-					Jobs: map[string]*model.Job{
-						"composite-job": {},
-					},
-				},
-			},
-			Config:           &configCopy,
-			StepResults:      map[string]*model.StepResult{},
-			JobContainer:     rc.JobContainer,
-			Inputs:           inputs,
-			ActionPath:       containerActionDir,
-			ActionRepository: rc.ActionRepository,
-			ActionRef:        rc.ActionRef,
-			Env:              env,
-			Masks:            rc.Masks,
-			ExtraPath:        rc.ExtraPath,
-		}
-
-		ctx = WithCompositeLogger(ctx, &compositerc.Masks)
-
-		// We need to inject a composite RunContext related command
-		// handler into the current running job container
-		// We need this, to support scoping commands to the composite action
-		// executing.
-		rawLogger := common.Logger(ctx).WithField("raw_output", true)
-		logWriter := common.NewLineWriter(compositerc.commandHandler(ctx), func(s string) bool {
-			if rc.Config.LogOutput {
-				rawLogger.Infof("%s", s)
-			} else {
-				rawLogger.Debugf("%s", s)
-			}
-			return true
-		})
-		oldout, olderr := compositerc.JobContainer.ReplaceLogWriter(logWriter, logWriter)
-		defer (func() {
-			rc.JobContainer.ReplaceLogWriter(oldout, olderr)
-		})()
-
-		err := runCompositeSteps(ctx, action, compositerc)
-
-		// Map outputs from composite RunContext to job RunContext
-		eval = compositerc.NewExpressionEvaluator()
-		for outputName, output := range action.Outputs {
-			rc.setOutput(ctx, map[string]string{
-				"name": outputName,
-			}, eval.Interpolate(output.Value))
-		}
-
-		rc.Masks = compositerc.Masks
-		rc.ExtraPath = compositerc.ExtraPath
-
-		return err
-	}
-}
-
-// Executor returns a pipeline executor for all the steps in the job
-func (rc *RunContext) compositeExecutor(action *model.Action) *compositeSteps {
-	steps := make([]common.Executor, 0)
-	preSteps := make([]common.Executor, 0)
-	postSteps := make([]common.Executor, 0)
-
-	sf := &stepFactoryImpl{}
-
-	for i, step := range action.Runs.Steps {
-		if step.ID == "" {
-			step.ID = fmt.Sprintf("%d", i)
-		}
-
-		// create a copy of the step, since this composite action could
-		// run multiple times and we might modify the instance
-		stepcopy := step
-
-		step, err := sf.newStep(&stepcopy, rc)
-		if err != nil {
-			return &compositeSteps{
-				main: common.NewErrorExecutor(err),
-			}
-		}
-
-		preSteps = append(preSteps, step.pre())
-
-		steps = append(steps, func(ctx context.Context) error {
-			err := step.main()(ctx)
-			if err != nil {
-				common.Logger(ctx).Errorf("%v", err)
-				common.SetJobError(ctx, err)
-			} else if ctx.Err() != nil {
-				common.Logger(ctx).Errorf("%v", ctx.Err())
-				common.SetJobError(ctx, ctx.Err())
-			}
-			return nil
-		})
-
-		postSteps = append([]common.Executor{step.post()}, postSteps...)
-	}
-
-	steps = append(steps, common.JobError)
-	return &compositeSteps{
-		pre: common.NewPipelineExecutor(preSteps...),
-		main: func(ctx context.Context) error {
-			return common.NewPipelineExecutor(steps...)(common.WithJobErrorContainer(ctx))
-		},
-		post: common.NewPipelineExecutor(postSteps...),
-	}
-}
-
-func runCompositeSteps(ctx context.Context, action *model.Action, compositerc *RunContext) error {
-	steps := compositerc.compositeExecutor(action)
-	var err error
-	if steps.pre != nil {
-		err = steps.pre(ctx)
-	}
-	if err == nil {
-		err = steps.main(ctx)
-	}
-	if err == nil && steps.post != nil {
-		err = steps.post(ctx)
-	}
-	return err
-}
-
 func populateEnvsFromSavedState(env *map[string]string, step actionStep, rc *RunContext) {
 	stepResult := rc.StepResults[step.getStepModel().ID]
 	if stepResult != nil {
diff --git a/pkg/runner/action_composite.go b/pkg/runner/action_composite.go
index 6509e645594..bb8cbaadda7 100644
--- a/pkg/runner/action_composite.go
+++ b/pkg/runner/action_composite.go
@@ -1,9 +1,179 @@
 package runner
 
-import "github.com/nektos/act/pkg/common"
+import (
+	"context"
+	"fmt"
+
+	"github.com/nektos/act/pkg/common"
+	"github.com/nektos/act/pkg/model"
+)
+
+func execAsComposite(step actionStep, containerActionDir string) common.Executor {
+	rc := step.getRunContext()
+	action := step.getActionModel()
+
+	return func(ctx context.Context) error {
+		// Disable some features of composite actions, only for feature parity with github
+		for _, compositeStep := range action.Runs.Steps {
+			if err := compositeStep.Validate(rc.Config.CompositeRestrictions); err != nil {
+				return err
+			}
+		}
+
+		eval := rc.NewExpressionEvaluator()
+
+		inputs := make(map[string]interface{})
+		for k, input := range action.Inputs {
+			inputs[k] = eval.Interpolate(input.Default)
+		}
+		if step.getStepModel().With != nil {
+			for k, v := range step.getStepModel().With {
+				inputs[k] = eval.Interpolate(v)
+			}
+		}
+
+		env := make(map[string]string)
+		for k, v := range rc.Env {
+			env[k] = eval.Interpolate(v)
+		}
+		for k, v := range step.getStepModel().Environment() {
+			env[k] = eval.Interpolate(v)
+		}
+
+		// run with the global config but without secrets
+		configCopy := *rc.Config
+		configCopy.Secrets = nil
+
+		// create a run context for the composite action to run in
+		compositerc := &RunContext{
+			Name:    rc.Name,
+			JobName: rc.JobName,
+			Run: &model.Run{
+				JobID: "composite-job",
+				Workflow: &model.Workflow{
+					Name: rc.Run.Workflow.Name,
+					Jobs: map[string]*model.Job{
+						"composite-job": {},
+					},
+				},
+			},
+			Config:           &configCopy,
+			StepResults:      map[string]*model.StepResult{},
+			JobContainer:     rc.JobContainer,
+			Inputs:           inputs,
+			ActionPath:       containerActionDir,
+			ActionRepository: rc.ActionRepository,
+			ActionRef:        rc.ActionRef,
+			Env:              env,
+			Masks:            rc.Masks,
+			ExtraPath:        rc.ExtraPath,
+		}
+
+		ctx = WithCompositeLogger(ctx, &compositerc.Masks)
+
+		// We need to inject a composite RunContext related command
+		// handler into the current running job container
+		// We need this, to support scoping commands to the composite action
+		// executing.
+		rawLogger := common.Logger(ctx).WithField("raw_output", true)
+		logWriter := common.NewLineWriter(compositerc.commandHandler(ctx), func(s string) bool {
+			if rc.Config.LogOutput {
+				rawLogger.Infof("%s", s)
+			} else {
+				rawLogger.Debugf("%s", s)
+			}
+			return true
+		})
+		oldout, olderr := compositerc.JobContainer.ReplaceLogWriter(logWriter, logWriter)
+		defer (func() {
+			rc.JobContainer.ReplaceLogWriter(oldout, olderr)
+		})()
+
+		err := runCompositeSteps(ctx, action, compositerc)
+
+		// Map outputs from composite RunContext to job RunContext
+		eval = compositerc.NewExpressionEvaluator()
+		for outputName, output := range action.Outputs {
+			rc.setOutput(ctx, map[string]string{
+				"name": outputName,
+			}, eval.Interpolate(output.Value))
+		}
+
+		rc.Masks = append(rc.Masks, compositerc.Masks...)
+		rc.ExtraPath = compositerc.ExtraPath
+
+		return err
+	}
+}
 
 type compositeSteps struct {
 	pre  common.Executor
 	main common.Executor
 	post common.Executor
 }
+
+// Executor returns a pipeline executor for all the steps in the job
+func (rc *RunContext) compositeExecutor(action *model.Action) *compositeSteps {
+	steps := make([]common.Executor, 0)
+	preSteps := make([]common.Executor, 0)
+	postSteps := make([]common.Executor, 0)
+
+	sf := &stepFactoryImpl{}
+
+	for i, step := range action.Runs.Steps {
+		if step.ID == "" {
+			step.ID = fmt.Sprintf("%d", i)
+		}
+
+		// create a copy of the step, since this composite action could
+		// run multiple times and we might modify the instance
+		stepcopy := step
+
+		step, err := sf.newStep(&stepcopy, rc)
+		if err != nil {
+			return &compositeSteps{
+				main: common.NewErrorExecutor(err),
+			}
+		}
+
+		preSteps = append(preSteps, step.pre())
+
+		steps = append(steps, func(ctx context.Context) error {
+			err := step.main()(ctx)
+			if err != nil {
+				common.Logger(ctx).Errorf("%v", err)
+				common.SetJobError(ctx, err)
+			} else if ctx.Err() != nil {
+				common.Logger(ctx).Errorf("%v", ctx.Err())
+				common.SetJobError(ctx, ctx.Err())
+			}
+			return nil
+		})
+
+		postSteps = append([]common.Executor{step.post()}, postSteps...)
+	}
+
+	steps = append(steps, common.JobError)
+	return &compositeSteps{
+		pre: common.NewPipelineExecutor(preSteps...),
+		main: func(ctx context.Context) error {
+			return common.NewPipelineExecutor(steps...)(common.WithJobErrorContainer(ctx))
+		},
+		post: common.NewPipelineExecutor(postSteps...),
+	}
+}
+
+func runCompositeSteps(ctx context.Context, action *model.Action, compositerc *RunContext) error {
+	steps := compositerc.compositeExecutor(action)
+	var err error
+	if steps.pre != nil {
+		err = steps.pre(ctx)
+	}
+	if err == nil {
+		err = steps.main(ctx)
+	}
+	if err == nil && steps.post != nil {
+		err = steps.post(ctx)
+	}
+	return err
+}